Merge branch 'master' of github.com:supabase/supabase
No files matched your search
@@ -6,13 +6,24 @@ on:
|
||||
- studio
|
||||
paths:
|
||||
- 'studio/**'
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
supabase/studio
|
||||
public.ecr.aws/t3w2s2c9/studio
|
||||
flavor: |
|
||||
latest=true
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
|
||||
- uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
@@ -35,10 +46,10 @@ jobs:
|
||||
|
||||
- uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: studio
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
supabase/studio:latest
|
||||
public.ecr.aws/t3w2s2c9/studio:latest
|
||||
context: studio
|
||||
target: production
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -1,64 +1,60 @@
|
||||
# Developing Supabase
|
||||
|
||||
- [Development Setup](#development-setup)
|
||||
- [Installing Dependencies](#installing-dependencies)
|
||||
- [Forking Supabase on GitHub](#forking-supabase-on-github)
|
||||
- [Building Supabase](#building-supabase)
|
||||
- [Choosing Directory](#choosing-directory)
|
||||
- [Start a Development Server](#start-a-development-server)
|
||||
- [Supabase Website Development Server](#supabase-website-development-server)
|
||||
- [Supabase Docs Development Server](#supabase-docs-development-server)
|
||||
- [Supabase Studio Development Server](#supabase-studio-development-server)
|
||||
1. [Development setup](#development-setup)
|
||||
- [Install dependencies](#install-dependencies)
|
||||
- [Fork the repository](#fork-the-repository)
|
||||
1. [Build Supabase](#build-supabase)
|
||||
- [Choose a directory](#choose-a-directory)
|
||||
1. [Start a development server](#start-a-development-server)
|
||||
- [Supabase Website](#supabase-website)
|
||||
- [Supabase Docs](#supabase-docs)
|
||||
- [Supabase Studio](#supabase-studio)
|
||||
1. [Create a pull request](#create-a-pull-request)
|
||||
|
||||
- [Common tasks](#common-tasks)
|
||||
- [Add a redirect](#add-a-redirect)
|
||||
- [Monorepo](#monorepo)
|
||||
- [Getting started](#getting-started)
|
||||
- [Shared components](#shared-components)
|
||||
- [Installing packages](#installing-packages)
|
||||
- [Development](#development)
|
||||
- [Common Tasks](#common-tasks)
|
||||
- [Adding Redirects](#adding-redirects)
|
||||
- [Finally](#finally)
|
||||
- [Community Channels](#community-channels)
|
||||
- [Community channels](#community-channels)
|
||||
|
||||
## Development Setup
|
||||
## Development setup
|
||||
|
||||
First off, thanks for your interest in Supabase and for wanting to contribute! before you begin, read the
|
||||
Thanks for your interest in Supabase and for wanting to contribute! Before you begin, read the
|
||||
[code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) and check out the
|
||||
[existing issues](https://github.com/supabase/supabase/issues).
|
||||
This document describes how to set up your development environment to build and test Supabase.
|
||||
|
||||
### Installing Dependencies
|
||||
### Install dependencies
|
||||
|
||||
Before you can build Supabase, you must install and configure the following dependencies on your
|
||||
machine:
|
||||
You need to install and configure the following dependencies on your machine to build Supabase:
|
||||
|
||||
- [Git](http://git-scm.com/)
|
||||
|
||||
- [Node.js v16.x (LTS)](http://nodejs.org)
|
||||
- [npm](https://www.npmjs.com/) version 7+ or [Yarn](https://yarnpkg.com/)
|
||||
|
||||
- [npm](https://www.npmjs.com/) version 7+.
|
||||
### Fork the repository
|
||||
|
||||
### Forking Supabase on GitHub
|
||||
To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase).
|
||||
|
||||
To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase). After you fork the repository, you may now begin editing the source code.
|
||||
## Build Supabase
|
||||
|
||||
## Building Supabase
|
||||
|
||||
To build Supabase, you clone the source code repository:
|
||||
|
||||
2. Clone your GitHub forked repository:
|
||||
1. Clone your GitHub forked repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/<github_username>/supabase.git
|
||||
```
|
||||
|
||||
3. Go to the Supabase directory:
|
||||
1. Go to the Supabase directory:
|
||||
```sh
|
||||
cd supabase
|
||||
```
|
||||
|
||||
### Choosing Directory
|
||||
### Choose a directory
|
||||
|
||||
Before you start a development server, you must choose if you want to work on the [Supabase Website](https://supabase.com), [Supabase Docs](https://supabase.com/docs), or [Supabase Studio](https://app.supabase.com).
|
||||
Choose if you want to work on the [Supabase Website](https://supabase.com), [Supabase Docs](https://supabase.com/docs), or [Supabase Studio](https://app.supabase.com).
|
||||
|
||||
1. Go to the [Supabase Website](https://supabase.com) directory
|
||||
|
||||
@@ -69,7 +65,7 @@ Before you start a development server, you must choose if you want to work on th
|
||||
Go to the [Supabase Docs](https://supabase.com/docs) directory
|
||||
|
||||
```sh
|
||||
cd web
|
||||
cd apps/reference
|
||||
```
|
||||
|
||||
Go to the [Supabase Studio](https://app.supabase.com) directory
|
||||
@@ -78,7 +74,7 @@ Before you start a development server, you must choose if you want to work on th
|
||||
cd studio
|
||||
```
|
||||
|
||||
2. Install npm dependencies:
|
||||
1. Install npm/yarn dependencies:
|
||||
|
||||
npm
|
||||
|
||||
@@ -92,19 +88,19 @@ Before you start a development server, you must choose if you want to work on th
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Start a Development Server
|
||||
## Start a development server
|
||||
|
||||
To debug code, and to see changes in real time, it is often useful to have a local HTTP server. Click one of the three links below to choose which development server you want to start.
|
||||
To debug code and to see your changes in real time, it is often useful to have a local HTTP server. Click one of the three links below to choose which development server you want to start.
|
||||
|
||||
- [Supabase Website](#Supabase-Website-Development-Server)
|
||||
- [Supabase Docs](#Supabase-Docs-Development-Server)
|
||||
- [Supabase Studio](#Supabase-Studio-Development-Server)
|
||||
- [Supabase Website](#supabase-website)
|
||||
- [Supabase Docs](#supabase-docs)
|
||||
- [Supabase Studio](#supabase-studio)
|
||||
|
||||
### Supabase Website Development Server
|
||||
### Supabase Website
|
||||
|
||||
The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) section below.
|
||||
|
||||
### Supabase Docs Development Server
|
||||
### Supabase Docs
|
||||
|
||||
1. Build development server
|
||||
|
||||
@@ -120,7 +116,7 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec
|
||||
yarn build
|
||||
```
|
||||
|
||||
2. Start development server
|
||||
1. Start development server
|
||||
|
||||
npm
|
||||
|
||||
@@ -134,13 +130,9 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec
|
||||
yarn start
|
||||
```
|
||||
|
||||
3. To access the local server, enter the following URL into your web browser:
|
||||
1. Access the local server in your web browser at http://localhost:3010/docs.
|
||||
|
||||
```sh
|
||||
http://localhost:3005/docs
|
||||
```
|
||||
|
||||
### Supabase Studio Development Server
|
||||
### Supabase Studio
|
||||
|
||||
1. Start development server
|
||||
|
||||
@@ -156,13 +148,22 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec
|
||||
yarn dev
|
||||
```
|
||||
|
||||
2. To access the local server, enter the following URL into your web browser:
|
||||
1. Access the local server in your web browser at http://localhost:8082/.
|
||||
See the [Supabase Studio readme](./studio/README.md) for more information.
|
||||
|
||||
```sh
|
||||
http://localhost:8082/
|
||||
```
|
||||
## Create a pull request
|
||||
|
||||
For more information on Supabase Studio, see the [Supabase Studio readme](./studio/README.md).
|
||||
After making your changes, open a pull request (PR). Once you submit your pull request, others from the Supabase team/community will review it with you.
|
||||
|
||||
Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors).
|
||||
|
||||
---
|
||||
|
||||
## Common tasks
|
||||
|
||||
### Add a redirect
|
||||
|
||||
Create a new entry in the [`next.config.js`](https://github.com/supabase/supabase/blob/master/apps/www/next.config.js) file in our main site.
|
||||
|
||||
## Monorepo
|
||||
|
||||
@@ -179,16 +180,12 @@ npm run dev # start all the applications
|
||||
|
||||
Then edit and visit any of the following sites:
|
||||
|
||||
- `/apps/www`: http://localhost:3000
|
||||
- The main website.
|
||||
- `/apps/reference`: http://localhost:3010
|
||||
- Reference Documentation.
|
||||
- `/apps/temp-docs`: http://localhost:3001
|
||||
- We are migrating the docs to a Next.js application.
|
||||
- `/apps/temp-community-forum`: http://localhost:3002
|
||||
- pulls all our github discussions into a nextjs site. Temporary/POC
|
||||
- `/apps/temp-community-tutorials`: http://localhost:3003
|
||||
- pulls all our DEV articles (which community members can write) into a nextjs site. Temporary/POC
|
||||
Site | Directory | Description | Local development server
|
||||
---- | --------- | ----------- | ------------------------
|
||||
[supabase.com](https://supabase.com) | `/apps/www` | The main website | http://localhost:3000
|
||||
[supabase.com/docs](https://supabase.com/docs) | `apps/reference` | Guides and Reference documentaion | http://localhost:3010/docs
|
||||
[POC] Community forum | `/apps/temp-community-forum` | GitHub Discussions in a Next.js site | http://localhost:3002
|
||||
[POC] DEV articles site | `/apps/temp-community-tutorials` | A Next.js site for our DEV articles (which community members can write) | http://localhost:3003
|
||||
|
||||
### Shared components
|
||||
|
||||
@@ -216,18 +213,8 @@ You do not need to install `devDependencies` in each workspace. These can all be
|
||||
|
||||
`npm run dev`
|
||||
|
||||
## Common Tasks
|
||||
---
|
||||
|
||||
### Adding Redirects
|
||||
## Community channels
|
||||
|
||||
To add a redirect, simple create a new entry in the [`next.config.js`](https://github.com/supabase/supabase/blob/master/apps/www/next.config.js) file in our main site.
|
||||
|
||||
## Finally
|
||||
|
||||
After making your changes to the file(s) you'd like to update, it's time to open a pull request. Once you submit your pull request, others from the Supabase team/community will review it with you.
|
||||
|
||||
Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors)
|
||||
|
||||
## Community Channels
|
||||
|
||||
Stuck somewhere? Have any questions? please join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
|
||||
Stuck somewhere? Have any questions? Join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Font import
|
||||
/*
|
||||
Font import
|
||||
*/
|
||||
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
@@ -30,7 +30,7 @@
|
||||
:root[data-theme='dark'] {
|
||||
/* See theme-specific "--custom" vars below */
|
||||
|
||||
/*
|
||||
/*
|
||||
Customization here for both Light and Dark themes
|
||||
*/
|
||||
--custom-font-base: 'Inter', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
@@ -71,7 +71,7 @@
|
||||
--custom-shadow-tl: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
--custom-shadow-xl: 0 30px 60px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
/*
|
||||
/*
|
||||
Infirma overrides with customization
|
||||
*/
|
||||
/* Colors */
|
||||
@@ -542,8 +542,8 @@ a.card:hover {
|
||||
line-height: calc(var(--ifm-spacing-vertical) * 1);
|
||||
}
|
||||
|
||||
/*
|
||||
Link chevrons
|
||||
/*
|
||||
Link chevrons
|
||||
*/
|
||||
.menu .menu__link.menu__link--sublist::after {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg alt="Arrow" xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6 38 38"><path fill="inherit" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path></svg>');
|
||||
|
||||
@@ -6,11 +6,9 @@ sidebar_label: Auth Server
|
||||
|
||||
# Supabase Auth Server
|
||||
|
||||
The Supabase Auth Server (GoTrue) is a JWT based API for managing users and issuing JWT tokens.
|
||||
The Supabase Auth Server (GoTrue) is a JSON Web Token (JWT)-based API for managing users and issuing access tokens.
|
||||
|
||||
GoTrue is a small open-source API written in golang, that can act as a self-standing API service for handling user registration and authentication for JAM projects.
|
||||
|
||||
It's based on OAuth2 and JWT and will handle user signup, authentication and custom user data.
|
||||
GoTrue is an open-source API written in Golang, that acts as a self-standing API service for handling user registration and authentication for JAM projects. It's based on OAuth2 and JWT and handles user signup, authentication, and custom user data.
|
||||
|
||||
## Client libraries
|
||||
|
||||
|
||||
@@ -11,280 +11,254 @@ A sample `.env` file is located in the [storage repository](https://github.com/s
|
||||
|
||||
Use this file to configure your environment variables for your Storage server.
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
|
||||
|
||||
## General {#general}
|
||||
|
||||
|
||||
|
||||
### `ANON_KEY` {#ANON_KEY}
|
||||
|
||||
A long-lived JWT with anonymous Postgres privileges.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `SERVICE_KEY` {#SERVICE_KEY}
|
||||
|
||||
A long-lived JWT with Postgres privileges to bypass Row Level Security.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `TENANT_ID` {#TENANT_ID}
|
||||
|
||||
The ID of a Storage tenant.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `REGION` {#REGION}
|
||||
|
||||
Region of your S3 bucket.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `GLOBAL_S3_BUCKET` {#GLOBAL_S3_BUCKET}
|
||||
|
||||
Name of your S3 bucket.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `POSTGREST_URL` {#POSTGREST_URL}
|
||||
|
||||
The URL of your PostgREST server.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `PGRST_JWT_SECRET` {#PGRST_JWT_SECRET}
|
||||
|
||||
A JWT Secret for the PostgREST database.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `DATABASE_URL` {#DATABASE_URL}
|
||||
|
||||
The URL of your Postgres database.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `PGOPTIONS` {#PGOPTIONS}
|
||||
|
||||
Additional configuration parameters for Postgres startup.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `FILE_SIZE_LIMIT` {#FILE_SIZE_LIMIT}
|
||||
|
||||
The maximum file size allowed.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `STORAGE_BACKEND` {#STORAGE_BACKEND}
|
||||
|
||||
The storage provider.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `FILE_STORAGE_BACKEND_PATH` {#FILE_STORAGE_BACKEND_PATH}
|
||||
|
||||
The location storage when the "STORAGE_BACKEND" is set to "file".
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
|
||||
|
||||
## Multi-tenant {#multitenant}
|
||||
|
||||
|
||||
|
||||
### `IS_MULTITENANT` {#IS_MULTITENANT}
|
||||
|
||||
Operate across multiple tenants.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `MULTITENANT_DATABASE_URL` {#MULTITENANT_DATABASE_URL}
|
||||
|
||||
The URL of the multitenant Postgres database.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `X_FORWARDED_HOST_REGEXP` {#X_FORWARDED_HOST_REGEXP}
|
||||
|
||||
TBD.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `POSTGREST_URL_SUFFIX` {#POSTGREST_URL_SUFFIX}
|
||||
|
||||
The suffix for the PostgREST instance.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `ADMIN_API_KEYS` {#ADMIN_API_KEYS}
|
||||
|
||||
Secure API key for administrative endpoints.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
### `ENCRYPTION_KEY` {#ENCRYPTION_KEY}
|
||||
|
||||
An key for encryting/decrypting secrets.
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Required: <code>true</code>
|
||||
</li>
|
||||
<li>
|
||||
Default: <code>None</code>
|
||||
</li>
|
||||
<li>Required: <code>true</code></li>
|
||||
<li>Default: <code>None</code></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
@@ -44,6 +44,127 @@ The link type
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
email_change_new
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
email_change_current
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
recovery
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
magiclink
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
invite
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
signup
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -12,7 +12,7 @@ Returns the session data, refreshing it if necessary.
|
||||
If no session is detected, the session returned will be null.
|
||||
|
||||
```js
|
||||
const { data, error } = supabase.auth.getSession()
|
||||
const { data, error } = await supabase.auth.getSession()
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -20,5 +20,5 @@ const { data, error } = supabase.auth.getSession()
|
||||
### Get the session data
|
||||
|
||||
```js
|
||||
const { data, error } = supabase.auth.getSession()
|
||||
const { data, error } = await supabase.auth.getSession()
|
||||
```
|
||||
@@ -11,7 +11,9 @@ import TabItem from '@theme/TabItem'
|
||||
Gets the current user details if there is an existing session.
|
||||
|
||||
```js
|
||||
const user = supabase.auth.getUser()
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@@ -50,11 +52,15 @@ Takes in an optional access token jwt. If no jwt is provided, getUser() will att
|
||||
### Get the logged in user with the current existing session
|
||||
|
||||
```js
|
||||
const user = supabase.auth.getUser()
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
```
|
||||
|
||||
### Get the logged in user with a custom access token jwt.
|
||||
|
||||
```js
|
||||
const user = supabase.auth.getUser(jwt)
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser(jwt)
|
||||
```
|
||||
@@ -41,6 +41,27 @@ No description provided.
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -61,6 +82,96 @@ The user's phone number.
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
options
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
captchaToken
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Verification token received when the user completes the captcha on the site.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
shouldCreateUser
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>boolean</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
If set to false, this method will not create a new user. Defaults to true.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -172,6 +283,10 @@ If set to false, this method will not create a new user. Defaults to true.
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
## Notes
|
||||
|
||||
- This method is used for passwordless sign-ins where an otp is sent to the user's email or phone number.
|
||||
|
||||
@@ -42,6 +42,27 @@ No description provided.
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -82,6 +103,96 @@ The user's password.
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
options
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
captchaToken
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Verification token received when the user completes the captcha on the site.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
password
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The user's password.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -153,6 +264,10 @@ Verification token received when the user completes the captcha on the site.
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
## Notes
|
||||
|
||||
- Requires either an email and password or a phone number and password.
|
||||
|
||||
@@ -42,6 +42,27 @@ No description provided.
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -82,6 +103,116 @@ The user's password.
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
options
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
captchaToken
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Verification token received when the user completes the captcha on the site.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
data
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The user's metadata.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
password
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The user's password.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
@@ -193,6 +324,10 @@ The redirect url embedded in the email link
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
## Notes
|
||||
|
||||
- By default, the user will need to verify their email address before logging in. If you would like to change this, you can disable "Email Confirmations" by going to Authentication -> Settings on [app.supabase.com](https://app.supabase.com)
|
||||
|
||||
@@ -42,6 +42,47 @@ No description provided.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
VerifyMobileOtpParams
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
VerifyEmailOtpParams
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -62,6 +62,67 @@ The value to filter with.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Record
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -62,6 +62,67 @@ The value to filter with.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Record
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -62,6 +62,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -61,6 +61,467 @@ The operator to filter with.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.wfts
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.phfts
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.plfts
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.fts
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.ov
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.adj
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.nxr
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.nxl
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.sr
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.sl
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.cd
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.cs
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.in
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.is
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.ilike
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.like
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.lte
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.lt
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.gte
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.gt
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.neq
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
not.eq
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
FilterOperator
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
---
|
||||
id: initializing
|
||||
title: 'Initializing'
|
||||
slug: /initializing
|
||||
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v2_legacy.yml
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
You can initialize a new Supabase client using the `createClient()` method.
|
||||
|
||||
The Supabase client is your entrypoint to the rest of the Supabase functionality
|
||||
and is the easiest way to interact with everything we offer within the Supabase ecosystem.
|
||||
|
||||
## Parameters
|
||||
|
||||
<ul className="method-list-group">
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
supabaseUrl
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The unique Supabase URL which is supplied when you create a new project in your project dashboard.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
supabaseKey
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The unique Supabase Key which is supplied when you create a new project in your project dashboard.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
SupabaseClientOptions
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
auth
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
autoRefreshToken
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>boolean</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Automatically refreshes the token for logged in users.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
cookieOptions
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Options passed to the gotrue-js instance
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
detectSessionInUrl
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>boolean</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Detect a session from the URL. Used for OAuth login callbacks.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
persistSession
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>boolean</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Whether to persist a logged in session to storage.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
storage
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
A storage provider. Used to store the logged in session.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
storageKey
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Optional key name used for storing tokens in local storage
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
db
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The Postgres schema which your tables belong to. Must be on the list of exposed schemas in Supabase. Defaults to 'public'.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
schema
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>SchemaName</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
global
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
fetch
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>Fetch</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
A custom `fetch` implementation.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
headers
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>Record</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Optional headers for initializing the client.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
realtime
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>RealtimeClientOptions</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
Options passed to the realtime-js instance
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
## Examples
|
||||
|
||||
### createClient()
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
// Create a single supabase client for interacting with your database
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key'
|
||||
)
|
||||
```
|
||||
|
||||
### With additional parameters
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const options = {
|
||||
db: {
|
||||
schema: 'public',
|
||||
},
|
||||
auth: {
|
||||
autoRefreshToken: true,
|
||||
persistSession: true,
|
||||
detectSessionInUrl: true,
|
||||
},
|
||||
global: {
|
||||
headers: { 'x-my-custom-header': 'my-app-name' },
|
||||
},
|
||||
}
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
options
|
||||
)
|
||||
```
|
||||
|
||||
### API schemas
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
// Provide a custom schema. Defaults to "public".
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
{
|
||||
db: { schema: 'other_schema' },
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard.
|
||||
Go to `Settings > API > Schema` and add the schema which you want to expose to the API.
|
||||
|
||||
Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema.
|
||||
|
||||
### Custom `fetch` implementation
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
{
|
||||
global: { fetch: fetch.bind(globalThis) },
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
`supabase-js` uses the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) library to make HTTP requests,
|
||||
but an alternative `fetch` implementation can be provided as an option.
|
||||
This is most useful in environments where `cross-fetch` is not compatible (for instance Cloudflare Workers).
|
||||
@@ -40,6 +40,47 @@ The values to insert.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Row
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
@@ -85,6 +126,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -81,6 +81,147 @@ the body of the request
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Record
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ReadableStream
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
FormData
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
File
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Blob
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ArrayBuffer
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -62,6 +62,47 @@ The value to filter with.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -108,6 +108,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -79,6 +79,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -64,6 +64,207 @@ The body of the file to be stored in the bucket.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
URLSearchParams
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ReadableStream
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ReadableStream
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
FormData
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
File
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Buffer
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Blob
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ArrayBufferView
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ArrayBuffer
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -64,6 +64,207 @@ The body of the file to be stored in the bucket.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
URLSearchParams
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
string
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ReadableStream
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ReadableStream
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
FormData
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
File
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Buffer
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Blob
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ArrayBufferView
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
ArrayBuffer
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -9,7 +9,7 @@ import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('*')
|
||||
.on('postgres_changes', { event: '*', schema: '*' }, (payload) => {
|
||||
console.log('Change received!', payload)
|
||||
@@ -89,14 +89,14 @@ A callback function that will be called when the channel receives a message.
|
||||
- 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.
|
||||
- The channel name must exactly match the schema/table/filter you want to listen to separated by semicolons. See below examples for additional context.
|
||||
- The channel name must exactly match the schema/table/filter you want to listen to separated by colons. See below examples for additional context.
|
||||
|
||||
## Examples
|
||||
|
||||
### Listen to all database changes
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('*')
|
||||
.on('postgres_changes', { event: '*', schema: '*' }, (payload) => {
|
||||
console.log('Change received!', payload)
|
||||
@@ -107,7 +107,7 @@ const myChannel = supabase
|
||||
### Listening to a specific table
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
@@ -122,7 +122,7 @@ const myChannel = supabase
|
||||
### Listening to inserts
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
@@ -144,7 +144,7 @@ alter table "your_table" replica identity full;
|
||||
```
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
@@ -166,7 +166,7 @@ alter table "your_table" replica identity full;
|
||||
```
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
@@ -183,7 +183,7 @@ const myChannel = supabase
|
||||
You can chain listeners if you want to listen to multiple events for each table.
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
@@ -203,7 +203,7 @@ const myChannel = supabase
|
||||
You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match.
|
||||
|
||||
```js
|
||||
const myChannel = supabase
|
||||
supabase
|
||||
.channel('public:countries:id=eq.200')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
|
||||
@@ -116,6 +116,67 @@ No description provided.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
websearch
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
phrase
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
plain
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -82,6 +82,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -40,6 +40,47 @@ The values to insert.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
<code>object</code>
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
Row
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>object</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
@@ -85,6 +126,67 @@ Count algorithm to use to count rows in a table.
|
||||
|
||||
<ul className="method-list-group">
|
||||
<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
estimated
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
planned
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
exact
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
literal
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
---
|
||||
id: initializing
|
||||
title: 'Initializing'
|
||||
slug: initializing
|
||||
custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
You can initialize a new Supabase client using the `createClient()` method.
|
||||
|
||||
The Supabase client is your entrypoint to the rest of the Supabase functionality
|
||||
and is the easiest way to interact with everything we offer within the Supabase ecosystem.
|
||||
|
||||
## Parameters
|
||||
|
||||
<ul className="method-list-group">
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
supabaseUrl
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The unique Supabase URL which is supplied when you create a new project in your project dashboard.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
supabaseKey
|
||||
</span>
|
||||
<span className="method-list-item-label-badge required">
|
||||
required
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>string</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
The unique Supabase Key which is supplied when you create a new project in your project dashboard.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
options
|
||||
</span>
|
||||
<span className="method-list-item-label-badge false">
|
||||
optional
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
<code>SupabaseClientOptions</code>
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
No description provided.
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
## Examples
|
||||
|
||||
### createClient()
|
||||
|
||||
<Tabs
|
||||
defaultValue="js"
|
||||
groupId="reference/supabase-js"
|
||||
values={[{ label: 'JavaScript', value: 'js' }]}>
|
||||
|
||||
<TabItem value="js">
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
// Create a single supabase client for interacting with your database
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key'
|
||||
)
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
||||
### With additional parameters
|
||||
|
||||
<Tabs
|
||||
defaultValue="js"
|
||||
groupId="reference/supabase-js"
|
||||
values={[{ label: 'JavaScript', value: 'js' }]}>
|
||||
|
||||
<TabItem value="js">
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const options = {
|
||||
schema: 'public',
|
||||
headers: { 'x-my-custom-header': 'my-app-name' },
|
||||
autoRefreshToken: true,
|
||||
persistSession: true,
|
||||
detectSessionInUrl: true,
|
||||
}
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
options
|
||||
)
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
||||
### API schemas
|
||||
|
||||
<Tabs
|
||||
defaultValue="js"
|
||||
groupId="reference/supabase-js"
|
||||
values={[{ label: 'JavaScript', value: 'js' }]}>
|
||||
|
||||
<TabItem value="js">
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
// Provide a custom schema. Defaults to "public".
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
{
|
||||
schema: 'other_schema',
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard.
|
||||
Go to `Settings > API > Schema` and add the schema which you want to expose to the API.
|
||||
|
||||
Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema.
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
||||
### Custom `fetch` implementation
|
||||
|
||||
<Tabs
|
||||
defaultValue="js"
|
||||
groupId="reference/supabase-js"
|
||||
values={[{ label: 'JavaScript', value: 'js' }]}>
|
||||
|
||||
<TabItem value="js">
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://xyzcompany.supabase.co',
|
||||
'public-anon-key',
|
||||
{
|
||||
fetch: fetch.bind(globalThis),
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
`supabase-js` uses the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) library to make HTTP requests,
|
||||
but an alternative `fetch` implementation can be provided as an option.
|
||||
This is most useful in environments where `cross-fetch` is not compatible (for instance Cloudflare Workers).
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
@@ -4,6 +4,7 @@ title: Introduction
|
||||
description: 'What is Supabase?'
|
||||
slug: /
|
||||
hide_table_of_contents: true
|
||||
pagination_next: null
|
||||
---
|
||||
|
||||
import ThemedImage from '@theme/ThemedImage'
|
||||
@@ -69,6 +70,26 @@ You can use it completely, or just the features you need.
|
||||
|
||||
<div class="container" style={{ padding: 0 }}>
|
||||
<div class="row is-multiline">
|
||||
{/* Auth */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={useBaseUrl('/guides/auth')}
|
||||
title={'Auth'}
|
||||
description={'User management with Row Level Security.'}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Auto-generated APIs */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={useBaseUrl('/guides/api')}
|
||||
title={'Auto-generated APIs'}
|
||||
description={'Instantly generate APIs for your database.'}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Database */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
@@ -79,17 +100,7 @@ You can use it completely, or just the features you need.
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* API */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={useBaseUrl('/guides/api')}
|
||||
title={'Auto-generated APIs'}
|
||||
description={'Instantly generate APIs for your database.'}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Functions */}
|
||||
{/* Edge Functions */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
@@ -99,17 +110,7 @@ You can use it completely, or just the features you need.
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Auth */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={useBaseUrl('/guides/auth')}
|
||||
title={'Auth'}
|
||||
description={'User management with Row Level Security.'}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Storage */}
|
||||
{/* File Storage */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
@@ -129,7 +130,16 @@ You can use it completely, or just the features you need.
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* */}
|
||||
{/* Realtime */}
|
||||
<div class="col col--4">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={useBaseUrl('/guides/realtime')}
|
||||
title={'Realtime'}
|
||||
description={'Build with Broadcast, Presence, and Postgres Changes.'}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
---
|
||||
id: auth-ui-overview
|
||||
title: Auth UI
|
||||
description: Securing your user data with Row Level Security.
|
||||
---
|
||||
|
||||
# Auth UI
|
||||
|
||||
Auth UI is a React component that provides a simple way to authenticate users.
|
||||
|
||||
It is currently only available for React, however it is planned to be available for other frameworks.
|
||||
|
||||
Auth UI relies on [@supabase/supabase-js](/docs/reference/javascript/next/). You need to also [install @supabase/supabase-js](/docs/reference/javascript/next/installing).
|
||||
|
||||
### Install via NPM
|
||||
|
||||
Install the NPM package from @supabase/react-ui-react
|
||||
|
||||
```bash
|
||||
npm install @supabase/react-ui-react @supabase/supabase-js@rc
|
||||
```
|
||||
|
||||
### Import Auth component
|
||||
|
||||
The simplest way to use the component is to pass `supabaseClient` from @supabase/supabase-js as a prop to the component.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => <Auth supabaseClient={supabase} />
|
||||
```
|
||||
|
||||
The example above renders the Auth component without any styling.
|
||||
|
||||
We recommend using one of the themes provided to style the UI.
|
||||
Import the theme you want to use and pass it to the `appearence.theme` prop.
|
||||
|
||||
```diff js title="/src/index.js"
|
||||
import {
|
||||
Auth,
|
||||
+ ThemeSupa
|
||||
} from '@supabase/react-ui-react'
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
+ appearance={{ theme: ThemeSupa }}
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
# Customizing Auth UI
|
||||
|
||||
Auth UI is a React component that provides a UI that 'works out of the box'.
|
||||
|
||||
There are several ways to customize Auth UI:
|
||||
|
||||
- Using one of the [predefined Themes](#themes) that comes with Auth UI.
|
||||
- Extending a theme by [overriding the variable tokens](#overwriting-themes) in a theme.
|
||||
- [Creating your own Theme](#creating-your-own-theme)
|
||||
- [Using your own CSS classes](#using-your-own-css-classes)
|
||||
- [Using inline styles](#using-your-own-inline-styles)
|
||||
- [Using your own labels](#using-your-own-custom-labels)
|
||||
|
||||
---
|
||||
|
||||
## Themes
|
||||
|
||||
### Predefined themes
|
||||
|
||||
Auth UI comes with several themes to customize the appearance.
|
||||
|
||||
Each predefined theme comes with at least 2 variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop.
|
||||
|
||||
Import the theme you want to use and pass it to the `appearence.theme` prop.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth, ThemeSupa } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} />
|
||||
)
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
Currently there is only 1 predefined theme available, but we plan to add more.
|
||||
|
||||
:::
|
||||
|
||||
### Switching theme variations
|
||||
|
||||
Auth UI comes with 2 theme variations: `default` and `dark`. You can switch between these themes by using the `theme` prop.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth, ThemeSupa } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{ theme: ThemeSupa }}
|
||||
theme="dark"
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
If you don't pass a value to `theme` it will use the `"default"` theme. You can pass `"dark"` to the theme prop to switch to the `dark` theme. If your theme has other variations, use the name of the variation in this prop.
|
||||
|
||||
## Overwriting themes
|
||||
|
||||
Auth UI themes can be overridden using variable tokens.
|
||||
|
||||
The available variable tokens [can be viewed here](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx).
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth, ThemeSupa } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{
|
||||
theme: ThemeSupa,
|
||||
variables: {
|
||||
default: {
|
||||
colors: {
|
||||
brand: 'red',
|
||||
brandAccent: 'darkred',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
If you are using a theme that you have created, you will probably not need to override any of the them.
|
||||
|
||||
## Creating your own theme
|
||||
|
||||
The available tokens within a theme [can be viewed here](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx). You can create your own theme by following the same structure within a `appearance.theme` property.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const customTheme = {
|
||||
default: {
|
||||
colors: {
|
||||
brand: 'hsl(153 60.0% 53.0%)',
|
||||
brandAccent: 'hsl(154 54.8% 45.1%)',
|
||||
brandButtonText: 'white',
|
||||
// ..
|
||||
},
|
||||
dark: {
|
||||
colors: {
|
||||
brandButtonText: 'white',
|
||||
defaultButtonBackground: '#2e2e2e',
|
||||
defaultButtonBackgroundHover: '#3e3e3e',
|
||||
//..
|
||||
},
|
||||
},
|
||||
// You can also add more theme variations with different names.
|
||||
evenDarker: {
|
||||
colors: {
|
||||
brandButtonText: 'white',
|
||||
defaultButtonBackground: '#1e1e1e',
|
||||
defaultButtonBackgroundHover: '#2e2e2e',
|
||||
//..
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
theme="default" // can also be "dark" or "evenDarker"
|
||||
appearance={{ theme: customTheme}}
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
You can swich between different variations of your theme [by using the "theme" prop](#switching-theme-variations).
|
||||
|
||||
## Custom CSS classes {#custom-css-classes}
|
||||
|
||||
You can use custom CSS classes with Auth UI.
|
||||
|
||||
The elements available that can have a CSS classname applied are the following:
|
||||
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{
|
||||
className: {
|
||||
anchor: 'my-awesome-anchor',
|
||||
button: 'my-awesome-button',
|
||||
//..
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
## Customized inline CSS {#custom-css-inline}
|
||||
|
||||
You can use custom CSS inline styles with Auth UI.
|
||||
|
||||
The elements available that can have CSS inline style applied are the following:
|
||||
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{
|
||||
style: {
|
||||
button: { background: 'red', color: 'white' },
|
||||
anchor: { color: 'blue' },
|
||||
//..
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
## Custom labels {#custom-labels}
|
||||
|
||||
You can use your own labels with Auth UI.
|
||||
|
||||
A breakdown of what labels can be overwritten [can be viewed on GitHub](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/lib/Localization/en.json).
|
||||
|
||||
You can add your custom labels to `localization.variables`.
|
||||
|
||||
```js title="/src/index.js"
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/react-ui-react'
|
||||
|
||||
const supabase = createClient(
|
||||
'<INSERT PROJECT URL>',
|
||||
'<INSERT PROJECT ANON API KEY>'
|
||||
)
|
||||
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
localization={{
|
||||
variables: {
|
||||
sign_in: {
|
||||
email_label: 'Your email address',
|
||||
password_label: 'Your strong password',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
```
|
||||
@@ -1,41 +1,66 @@
|
||||
---
|
||||
id: platform
|
||||
title: Supabase Platform
|
||||
description: Getting started with the Supabase platform.
|
||||
description: Getting started with the Supabase Platform.
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||
|
||||
Supabase is a hosted platform which makes it very simple to get started without needing to manage any infrastructure.
|
||||
|
||||
Visit [app.supabase.com](https://app.supabase.com) and sign in to start creating projects.
|
||||
|
||||
## Organizations
|
||||
|
||||
Organizations are a way to group your projects. Every Organization can be configured with different Team members and billing settings.
|
||||
|
||||
### Managing Team Members
|
||||
|
||||
You can invite your Team members into your Organizations so that you can collaborate on projects.
|
||||
|
||||
<video width="99%" muted playsInline controls="true">
|
||||
<source
|
||||
src={useBaseUrl('/videos/invite-team.mp4')}
|
||||
type="video/mp4"
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
</video>
|
||||
|
||||
## Projects
|
||||
|
||||
Each project on Supabase comes with these features:
|
||||
|
||||
- A dedicated Postgres database. [Learn more](../../guides/database)
|
||||
- Auto-generated APIs. [Learn more](../../guides/api)
|
||||
- Auth and User management. [Learn more](../../guides/auth)
|
||||
- Storage. [Learn more](../../guides/storage)
|
||||
- A dedicated Postgres database. [Learn more](/docs/guides/database)
|
||||
- Auto-generated APIs. [Learn more](/docs/guides/api)
|
||||
- Auth and User management. [Learn more](/docs/guides/auth)
|
||||
- Storage. [Learn more](/docs/guides/storage)
|
||||
|
||||
## Next Steps
|
||||
## Organizations
|
||||
|
||||
- Sign in to [app.supabase.com](https://app.supabase.com)
|
||||
Organizations are a way to group your projects. Each organization can be configured with different team members and billing settings.
|
||||
|
||||
## Manage team members
|
||||
|
||||
You can invite your team members into your organizations to collaborate on projects.
|
||||
|
||||
<video width="99%" muted playsInline controls="true">
|
||||
<source src="/docs/videos/invite-team.mp4" type="video/mp4" muted playsInline />
|
||||
</video>
|
||||
|
||||
You can also assign roles to your team members with different access levels. The table below shows the corresponding permissions for each available role in the Dashboard.
|
||||
|
||||
| Permissions | Owner | Administrator | Developer |
|
||||
| ---------------------------- | ----- | ------------- | --------- |
|
||||
| **Organization** |
|
||||
| Can change organization name | ✅ | | |
|
||||
| Can delete organization | ✅ | | |
|
||||
| **Members** |
|
||||
| Can add an Owner | ✅ | | |
|
||||
| Can remove an Owner | ✅ | | |
|
||||
| Can add an Adminstrator | ✅ | ✅ | |
|
||||
| Can remove an Administrator | ✅ | ✅ | |
|
||||
| Can add a Developer | ✅ | ✅ | |
|
||||
| Can remove a Developer | ✅ | ✅ | |
|
||||
| Can revoke an invite | ✅ | ✅ | |
|
||||
| Can resend an invite | ✅ | ✅ | |
|
||||
| **Billing** |
|
||||
| Can read invoices | ✅ | ✅ | ✅ |
|
||||
| Can read billing email | ✅ | ✅ | ✅ |
|
||||
| Can change billing email | ✅ | | |
|
||||
| Can view subscription | ✅ | ✅ | ✅ |
|
||||
| Can update subscription | ✅ | ✅ | |
|
||||
| Can read billing address | ✅ | ✅ | ✅ |
|
||||
| Can update billing address | ✅ | ✅ | |
|
||||
| Can read tax codes | ✅ | ✅ | ✅ |
|
||||
| Can update tax codes | ✅ | ✅ | |
|
||||
| Can read payment methods | ✅ | ✅ | ✅ |
|
||||
| Can update payment methods | ✅ | ✅ | |
|
||||
| **Projects** |
|
||||
| Can create a project | ✅ | ✅ | |
|
||||
| Can delete a project | ✅ | ✅ | |
|
||||
| Can update a project | ✅ | ✅ | |
|
||||
| Can pause a project | ✅ | ✅ | |
|
||||
| Can resume a project | ✅ | ✅ | |
|
||||
| Can restart a project | ✅ | ✅ | ✅ |
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: realtime
|
||||
title: Realtime
|
||||
description: Using Supabase Realtime for multiplayer functionality.
|
||||
sidebar_label: Overview
|
||||
---
|
||||
|
||||
Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime).
|
||||
|
||||
You can use this to:
|
||||
|
||||
- broadcast messages between users
|
||||
- manage shared state between users
|
||||
- listen to database changes over websockets
|
||||
|
||||
## Realtime Channels
|
||||
|
||||
In Realtime, everything is a [_channel_](https://hexdocs.pm/phoenix/channels.html).
|
||||
Channels are like chatrooms where participants can join and leave—similar to Slack or Discord channels.
|
||||
|
||||
### Broadcast
|
||||
|
||||
Broadcast follows the classic Publisher/Subscriber pattern. A client (publisher) “broadcasts” messages using a unique identifier. For example, a user could send a message to a `#random` channel.
|
||||
|
||||
Other clients (subscribers) can “listen” to these messages in real-time, using the unique identifier. If they are listening to the `#random` channel, then they will receive the message.
|
||||
|
||||
A common use-case for Broadcast is sharing a user's cursor position with other clients in an online game.
|
||||
|
||||
### Presence
|
||||
|
||||
Presence synchronizes shared state between users.
|
||||
Presence is very similar to Broadcast, except that the state is “persisted” in the Channel
|
||||
so that new joiners immediately receive the state without waiting for another user to broadcast it.
|
||||
In our Slack example, when you turn on Slack you can see who's online without each individual user
|
||||
sending an “I'm online” message to the new-joiner. Presence utilizes Broadcast as the transport layer.
|
||||
|
||||
The neat thing about Presence is that if a user is suddenly disconnected (for example, they go offline), their state will be automatically removed from the shared state.
|
||||
If you've ever tried to build an “I'm online” feature which handles unexpected disconnects, you'll appreciate how useful this is.
|
||||
|
||||
### Database changes
|
||||
|
||||
You can subscribe to database changes using Realtime.
|
||||
The Realtime API works through PostgreSQL's replication functionality. Postgres sends database changes to a [publication](/docs/guides/database/replication#publications)
|
||||
called `supabase_realtime`, and by managing this publication you can control which data is broadcast.
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: broadcast
|
||||
title: Broadcast
|
||||
description: Getting started with Realtime's Broadcast feature
|
||||
---
|
||||
|
||||
Supabase Broadcast allows a client to send messages, and multiple receivers to receive the messages.
|
||||
|
||||
The broadcasted messages are ephemeral. They are not persisted to the database and are directly relayed through the Realtime server. This is ideal for sending information like mouse moments where latency is important, but need not be persisted.
|
||||
|
||||
The broadcast JS client methods are supported from supabase-js v2 release candidate.
|
||||
|
||||
To broadcast a message:
|
||||
|
||||
```js
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL,
|
||||
process.env.SUPABASE_KEY
|
||||
)
|
||||
|
||||
// The name of the channel can be set to any string.
|
||||
// Set the same name across both the broadcasting and receiving clients.
|
||||
const channel = supabase.channel('user1-location', {
|
||||
configs: {
|
||||
broadcast: { ack: true },
|
||||
},
|
||||
})
|
||||
|
||||
// subscribe registers your client with the server
|
||||
channel.subscribe(async (status) => {
|
||||
if (status === 'SUBSCRIBED') {
|
||||
// now you can start broadcasting messages
|
||||
// sending a new message every second
|
||||
setInterval(async () => {
|
||||
const status = await channel.send({
|
||||
type: 'broadcast',
|
||||
event: 'location',
|
||||
payload: { x: Math.random(), y: Math.random() },
|
||||
})
|
||||
console.log(status)
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
To receive the broadcasted message, run this script in another tab:
|
||||
|
||||
```js
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL,
|
||||
process.env.SUPABASE_KEY
|
||||
)
|
||||
|
||||
// use the same channel name as the client broadcasting the message is using
|
||||
const channel = supabase.channel('user1-location')
|
||||
|
||||
// listen to broadcasts
|
||||
channel
|
||||
.on('broadcast', { event: 'location' }, (payload) => console.log(payload))
|
||||
.subscribe(async (status) => {
|
||||
if (status === 'SUBSCRIBED') {
|
||||
console.log(status)
|
||||
// your callback function will now be called with the received messages
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
id: postgres-changes
|
||||
title: Postgres Changes
|
||||
description: Getting started with Realtime's Postgres Changes feature
|
||||
---
|
||||
|
||||
Supabase Postgres Changes enable clients to listen Postgres database events, specifically INSERT, UPDATE, and DELETE events.
|
||||
|
||||
Clients can elect to get changes for all tables in the public schema, a specific table, or a specific column's value.
|
||||
|
||||
The postgres changes functionality is supported by supabase-js v2 release candidate.
|
||||
|
||||
To listen to all events on all tables in the public schema:
|
||||
|
||||
```js
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL,
|
||||
process.env.SUPABASE_KEY
|
||||
)
|
||||
|
||||
/*
|
||||
The name of the channel can be set to any string.
|
||||
Event can be either INSERT, UPDATE, DELETE, or * for all events.
|
||||
*/
|
||||
const channel = supabase
|
||||
.channel('db-changes')
|
||||
.on('postgres_changes', { event: '*', schema: '*' }, (payload) =>
|
||||
console.log(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
|
||||
To listen to INSERT events on the messages table in the public schema:
|
||||
|
||||
```js
|
||||
// Setup
|
||||
|
||||
const channel = supabase
|
||||
.channel('db-changes')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{ event: 'INSERT', schema: 'public', table: 'messages' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
|
||||
To listen to UPDATE events only when a specific column matches a value:
|
||||
|
||||
```js
|
||||
// Setup
|
||||
|
||||
const channel = supabase
|
||||
.channel('db-changes')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{ event: 'UPDATE', schema: 'public', table: 'messages', filter: 'id=eq.1' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
|
||||
Clients can also mix and match and listen to different events and schema/tables/filters:
|
||||
|
||||
```js
|
||||
// Setup
|
||||
|
||||
const channel = supabase
|
||||
.channel('db-changes')
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{ event: '*', schema: 'public', table: 'messages', filter: 'id=eq.23' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
.on(
|
||||
'postgres_changes',
|
||||
{ event: 'INSERT', schema: 'public', table: 'users' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: presence
|
||||
title: Presence
|
||||
description: Getting started with Realtime's presence feature
|
||||
---
|
||||
|
||||
Supabase Presence stores and synchronize shared state across clients. Presence is very similar to Broadcast, except that the state is “persisted” in the Channel so that new joiners can immediately get the state without waiting for another user to broadcast a message.
|
||||
|
||||
The `sync` event is triggered whenever the shared state changes. The `join` event is triggered when a new client joins the channel and `leave` when a client leaves.
|
||||
|
||||
Each client can use the `track` method to store an object in the shared state. Each client can only track one object in the shared state. If `track` is called again by the same client, then the new object will overwrite the previously tracked object in the shared state.
|
||||
|
||||
The presence JS client methods are supported from supabase-js v2 release candidate.
|
||||
|
||||
```js
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL,
|
||||
process.env.SUPABASE_KEY
|
||||
)
|
||||
|
||||
const channel = supabase.channel('online-users')
|
||||
|
||||
function getRandomUser() {
|
||||
const users = ['Alice', 'Bob', 'Mallory', 'Inian']
|
||||
return users[Math.floor(Math.random() * users.length)]
|
||||
}
|
||||
|
||||
channel
|
||||
.on('presence', { event: 'sync' }, () => {
|
||||
console.log('currently online users', channel.presenceState())
|
||||
})
|
||||
.on('presence', { event: 'join' }, ({ newUser }) => {
|
||||
console.log('a new user has joined', newUser)
|
||||
})
|
||||
.on('presence', { event: 'leave' }, ({ leftUser }) =>
|
||||
console.log('a user has left', leftUser)
|
||||
)
|
||||
.subscribe(async (status) => {
|
||||
if (status === 'SUBSCRIBED') {
|
||||
const status = await channel.track({ user_name: getRandomUser() })
|
||||
console.log(status)
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -168,10 +168,10 @@ npx create-react-app supabase-react
|
||||
cd supabase-react
|
||||
```
|
||||
|
||||
Then let's install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js)
|
||||
Then let's install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js). We're going to install the "rc" (release candidate) version until this is released for general use.
|
||||
|
||||
```bash
|
||||
npm install @supabase/supabase-js
|
||||
npm install @supabase/supabase-js@rc
|
||||
```
|
||||
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
@@ -195,7 +195,7 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
```
|
||||
|
||||
And one optional step is to update the CSS file `src/index.css` to make the app look nice.
|
||||
You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/react-user-management/src/index.css).
|
||||
You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/examples/main/supabase-js-v2/user-management/react-user-management/src/index.css).
|
||||
|
||||
### Set up a Login component
|
||||
|
||||
@@ -214,7 +214,7 @@ export default function Auth() {
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
const { error } = await supabase.auth.signIn({ email })
|
||||
const { error } = await supabase.auth.signInWithOtp({ email })
|
||||
if (error) throw error
|
||||
alert('Check your email for the login link!')
|
||||
} catch (error) {
|
||||
@@ -278,7 +278,7 @@ const Account = ({ session }) => {
|
||||
const getProfile = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const user = supabase.auth.user()
|
||||
const { user } = session
|
||||
|
||||
let { data, error, status } = await supabase
|
||||
.from('profiles')
|
||||
@@ -307,7 +307,7 @@ const Account = ({ session }) => {
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
const user = supabase.auth.user()
|
||||
const { user } = session
|
||||
|
||||
const updates = {
|
||||
id: user.id,
|
||||
@@ -317,9 +317,7 @@ const Account = ({ session }) => {
|
||||
updated_at: new Date(),
|
||||
}
|
||||
|
||||
let { error } = await supabase.from('profiles').upsert(updates, {
|
||||
returning: 'minimal', // Don't return the value after inserting
|
||||
})
|
||||
let { error } = await supabase.from('profiles').upsert(updates)
|
||||
|
||||
if (error) {
|
||||
throw error
|
||||
@@ -392,7 +390,9 @@ export default function App() {
|
||||
const [session, setSession] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
setSession(supabase.auth.session())
|
||||
supabase.auth.getSession().then(({ data: { session } }) => {
|
||||
setSession(session)
|
||||
})
|
||||
|
||||
supabase.auth.onAuthStateChange((_event, session) => {
|
||||
setSession(session)
|
||||
|
||||
@@ -9,7 +9,7 @@ import Link from '@docusaurus/Link'
|
||||
import ButtonCard from '@site/src/components/ButtonCard'
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||
|
||||
The Supabase Reference Docs provide technical descriptions of the products and how to use them.
|
||||
Reference documentation for the official Supabase client libraries, APIs, and tools.
|
||||
|
||||
<div class="container" style={{ padding: 0 }}>
|
||||
<div class="row is-multiline">
|
||||
@@ -30,11 +30,11 @@ The Supabase Reference Docs provide technical descriptions of the products and h
|
||||
</div>
|
||||
{/* CLI */}
|
||||
<div class="col col--6">
|
||||
<ButtonCard icon={useBaseUrl("/img/icons/cli-icon.svg")} class="card" to={useBaseUrl("/reference/cli")} style={{ height: '100%' }} title="Supabase CLI" description="Manage your Supabase projects."/>
|
||||
<ButtonCard icon={useBaseUrl("/img/icons/cli-icon.svg")} class="card" to={useBaseUrl("/reference/cli")} style={{ height: '100%' }} title="Supabase CLI" description="Tools for developing your Supabase projects locally."/>
|
||||
</div>
|
||||
{/* API */}
|
||||
<div class="col col--6">
|
||||
<ButtonCard icon={useBaseUrl("/img/icons/api-icon.svg")} class="card" to={useBaseUrl("/reference/api")} style={{ height: '100%' }} title="Supabase API" description="Manage your Supabase projects."/>
|
||||
<ButtonCard icon={useBaseUrl("/img/icons/api-icon.svg")} class="card" to={useBaseUrl("/reference/api")} style={{ height: '100%' }} title="Supabase API" description="Manage your Supabase organizations and projects."/>
|
||||
</div>
|
||||
{/* */}
|
||||
|
||||
@@ -43,7 +43,7 @@ The Supabase Reference Docs provide technical descriptions of the products and h
|
||||
|
||||
## Community
|
||||
|
||||
The Supabase Reference Docs provide technical descriptions of the products and how to use them.
|
||||
Reference documentation for community-contributed utilities.
|
||||
|
||||
<div class="container" style={{ padding: 0 }}>
|
||||
<div class="row is-multiline">
|
||||
@@ -54,17 +54,16 @@ The Supabase Reference Docs provide technical descriptions of the products and h
|
||||
to={useBaseUrl('/reference/auth-helpers')}
|
||||
style={{ height: '100%' }}
|
||||
title="Auth Helpers"
|
||||
description="A collection of framework specific Auth utilities for working with
|
||||
Supabase."
|
||||
description="Collection of framework-specific auth utilities for working with Supabase."
|
||||
/>
|
||||
</div>
|
||||
{/* */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Self-Hosting
|
||||
## Self-hosting
|
||||
|
||||
The Supabase Reference Docs provide technical descriptions of the products and how to use them.
|
||||
Reference documentation for self-hosting Supabase features.
|
||||
|
||||
<div class="container" style={{ padding: 0 }}>
|
||||
<div class="row is-multiline">
|
||||
@@ -75,7 +74,7 @@ The Supabase Reference Docs provide technical descriptions of the products and h
|
||||
to={useBaseUrl('/reference/auth')}
|
||||
style={{ height: '100%' }}
|
||||
title={'Auth Server'}
|
||||
description="Auth reference"
|
||||
description=" JSON Web Token (JWT)-based API for managing users and issuing access tokens."
|
||||
/>
|
||||
</div>
|
||||
{/* */}
|
||||
@@ -85,7 +84,7 @@ The Supabase Reference Docs provide technical descriptions of the products and h
|
||||
to={useBaseUrl('/reference/storage')}
|
||||
style={{ height: '100%' }}
|
||||
title={'Storage'}
|
||||
description="Storage reference"
|
||||
description="S3-compatible object storage service that integrates with Postgres."
|
||||
/>
|
||||
</div>
|
||||
{/* */}
|
||||
|
||||
@@ -14,7 +14,7 @@ const buildNavbar = ({ baseUrl }) => {
|
||||
position: 'left',
|
||||
activeBaseRegex: `^/${trimmedBaseUrl}/reference$|^/${trimmedBaseUrl}/reference/$`, // exactly match "/${trimmedBaseUrl}/reference/" only
|
||||
},
|
||||
{ href: 'https://app.supabase.com', label: 'Login', position: 'right' },
|
||||
{ href: 'https://app.supabase.com', label: 'Dashboard', position: 'right' },
|
||||
{
|
||||
href: 'https://github.com/supabase/supabase',
|
||||
className: 'navbar-item-github',
|
||||
|
||||
@@ -42,56 +42,6 @@ const sidebars = {
|
||||
'guides/cli/cicd-workflow',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Database',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database',
|
||||
'guides/database/connecting-to-postgres',
|
||||
'guides/database/tables',
|
||||
'guides/database/functions',
|
||||
'guides/database/full-text-search',
|
||||
// 'guides/database/json',
|
||||
// 'guides/database/arrays',
|
||||
// 'guides/database/sql-to-api',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Extensions',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database/extensions',
|
||||
// 'guides/database/extensions/pgtap',
|
||||
'guides/database/extensions/plv8',
|
||||
'guides/database/extensions/http',
|
||||
'guides/database/extensions/uuid-ossp',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Configuration',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database/timeouts',
|
||||
'guides/database/replication',
|
||||
'guides/database/managing-passwords',
|
||||
'guides/database/managing-timezones',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'APIs',
|
||||
collapsed: true,
|
||||
items: ['guides/api', 'guides/api/generating-types'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Functions',
|
||||
collapsed: true,
|
||||
items: ['guides/functions'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Auth',
|
||||
@@ -136,6 +86,12 @@ const sidebars = {
|
||||
'guides/auth/managing-user-data',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Auth Helpers',
|
||||
collapsed: true,
|
||||
items: ['guides/auth/auth-helpers/auth-ui-overview'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Deep Dive',
|
||||
@@ -150,6 +106,56 @@ const sidebars = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'APIs',
|
||||
collapsed: true,
|
||||
items: ['guides/api', 'guides/api/generating-types'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Database',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database',
|
||||
'guides/database/connecting-to-postgres',
|
||||
'guides/database/tables',
|
||||
'guides/database/functions',
|
||||
'guides/database/full-text-search',
|
||||
// 'guides/database/json',
|
||||
// 'guides/database/arrays',
|
||||
// 'guides/database/sql-to-api',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Extensions',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database/extensions',
|
||||
// 'guides/database/extensions/pgtap',
|
||||
'guides/database/extensions/plv8',
|
||||
'guides/database/extensions/http',
|
||||
'guides/database/extensions/uuid-ossp',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Configuration',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database/timeouts',
|
||||
'guides/database/replication',
|
||||
'guides/database/managing-passwords',
|
||||
'guides/database/managing-timezones',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Functions',
|
||||
collapsed: true,
|
||||
items: ['guides/functions'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Storage',
|
||||
@@ -168,6 +174,17 @@ const sidebars = {
|
||||
'guides/platform/permissions',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Realtime',
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/realtime',
|
||||
'guides/realtime/broadcast',
|
||||
'guides/realtime/presence',
|
||||
'guides/realtime/postgres-changes',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Self Hosting',
|
||||
@@ -181,6 +198,7 @@ const sidebars = {
|
||||
items: [
|
||||
'guides/integrations/appsmith',
|
||||
'guides/integrations/auth0',
|
||||
'guides/integrations/authsignal',
|
||||
'guides/integrations/clerk',
|
||||
'guides/integrations/dashibase',
|
||||
'guides/integrations/directus',
|
||||
@@ -217,8 +235,6 @@ const sidebars = {
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ type: 'doc', id: 'reference' },
|
||||
{ type: 'link', label: 'Supabase CLI', href: '/reference/cli' },
|
||||
{ type: 'link', label: 'Supabase API', href: '/reference/api' },
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Supabase JavaScript Library',
|
||||
@@ -229,6 +245,8 @@ const sidebars = {
|
||||
label: 'Supabase Dart Library',
|
||||
href: '/reference/dart',
|
||||
},
|
||||
{ type: 'link', label: 'Supabase CLI', href: '/reference/cli' },
|
||||
{ type: 'link', label: 'Supabase API', href: '/reference/api' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -246,7 +264,7 @@ const sidebars = {
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Self hosted',
|
||||
label: 'Self-hosting',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ type: 'link', label: 'Auth Server', href: '/reference/auth' },
|
||||
|
||||
@@ -23,7 +23,7 @@ const sidebars = {
|
||||
items: [
|
||||
'intro',
|
||||
'installing',
|
||||
'initializing',
|
||||
'generated/initializing',
|
||||
'typescript-support',
|
||||
'release-notes',
|
||||
],
|
||||
@@ -78,6 +78,50 @@ const sidebars = {
|
||||
'generated/upsert',
|
||||
'generated/delete',
|
||||
'generated/rpc',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Modifiers',
|
||||
items: [
|
||||
'generated/using-modifiers',
|
||||
'generated/limit',
|
||||
'generated/order',
|
||||
'generated/range',
|
||||
'generated/single',
|
||||
'generated/maybesingle',
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Filters',
|
||||
items: [
|
||||
'generated/using-filters',
|
||||
'generated/or',
|
||||
'generated/not',
|
||||
'generated/match',
|
||||
'generated/eq',
|
||||
'generated/neq',
|
||||
'generated/gt',
|
||||
'generated/gte',
|
||||
'generated/lt',
|
||||
'generated/lte',
|
||||
'generated/like',
|
||||
'generated/ilike',
|
||||
'generated/is',
|
||||
'generated/in',
|
||||
'generated/contains',
|
||||
'generated/containedby',
|
||||
'generated/rangelt',
|
||||
'generated/rangegt',
|
||||
'generated/rangegte',
|
||||
'generated/rangelte',
|
||||
'generated/rangeadjacent',
|
||||
'generated/overlaps',
|
||||
'generated/textsearch',
|
||||
'generated/filter',
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
@@ -115,50 +159,6 @@ const sidebars = {
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Modifiers',
|
||||
items: [
|
||||
'generated/using-modifiers',
|
||||
'generated/limit',
|
||||
'generated/order',
|
||||
'generated/range',
|
||||
'generated/single',
|
||||
'generated/maybesingle',
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Filters',
|
||||
items: [
|
||||
'generated/using-filters',
|
||||
'generated/or',
|
||||
'generated/not',
|
||||
'generated/match',
|
||||
'generated/eq',
|
||||
'generated/neq',
|
||||
'generated/gt',
|
||||
'generated/gte',
|
||||
'generated/lt',
|
||||
'generated/lte',
|
||||
'generated/like',
|
||||
'generated/ilike',
|
||||
'generated/is',
|
||||
'generated/in',
|
||||
'generated/contains',
|
||||
'generated/containedby',
|
||||
'generated/rangelt',
|
||||
'generated/rangegt',
|
||||
'generated/rangegte',
|
||||
'generated/rangelte',
|
||||
'generated/rangeadjacent',
|
||||
'generated/overlaps',
|
||||
'generated/textsearch',
|
||||
'generated/filter',
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
// {
|
||||
// type: "category",
|
||||
// label: "Release Notes",
|
||||
|
||||
@@ -33,6 +33,7 @@ h4.method-list-item-label .method-list-item-label-name {
|
||||
}
|
||||
|
||||
h4.method-list-item-label .method-list-item-label-badge {
|
||||
overflow-wrap: anywhere;
|
||||
font-family: var(--ifm-font-family-monospace);
|
||||
color: var(--ifm-font-color-base);
|
||||
font-size: var(--custom-font-size-xs);
|
||||
|
||||
@@ -239,8 +239,8 @@ We have a lot more Enterprise features under development, available to early-acc
|
||||
|
||||
### SOC2
|
||||
|
||||
We are actively working towards our SOC2 Type II certification by monitoring and patching alerts raised by our security monitoring platform.
|
||||
SOC2 covers a wide spectrum of potential security areas and achieving SOC2 would also ease compliance with other major certifications like ISO-27001 and HIPAA.
|
||||
Supabase is now SOC2 Type 1 compliant, as announced during Launch Week 5. You can read all about the process we went through to get there in this [blog post](https://supabase.com/blog/supabase-soc2). Getting the Type 1 certification is just the start, and we will be working on getting certified for SOC2 Type 2 and HIPAA next.
|
||||
|
||||
|
||||
### Log ingestion
|
||||
|
||||
|
||||
@@ -115,10 +115,13 @@ Don't forget to checkout the new feature's being announced as part of [Launch We
|
||||
|
||||
- [Supabase Series B](https://supabase.com/blog/supabase-series-b)
|
||||
- [Open Source at Supabase - Founders Fireside Chat](https://www.youtube.com/watch?v=4t_63HT3rZY)
|
||||
- [supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Day 1 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
- [Day 2 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
- [Day 3 - Supabase is SOC2 compliant](https://supabase.com/blog/supabase-soc2)
|
||||
- [Youtube video - Security Day](https://www.youtube.com/watch?v=6bGQotxisoY)
|
||||
|
||||
|
||||
### Additional Info
|
||||
|
||||
|
||||
@@ -183,7 +183,9 @@ If you're already working towards the same goals, reach out and let's do it toge
|
||||
Launch Week 5 is starting Monday 15th August, we will launch one new feature every day for a week. If you want to follow along check out [supabase.com/launch-week](https://supabase.com/launch-week).
|
||||
|
||||
- [Launch Week 5 Hackathon](https://supabase.com/blog/launch-week-5-hackathon)
|
||||
- [Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [DAy 1 - Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [Youtube video - Supabase CLI v1 and Admin API Beta](https://www.youtube.com/watch?v=OpPOaJI_Z28&feature=emb_title)
|
||||
- [Day 2 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
- [Day 3 - Supabase is SOC2 compliant](https://supabase.com/blog/supabase-soc2)
|
||||
- [Youtube video - Security Day](https://www.youtube.com/watch?v=6bGQotxisoY)
|
||||
@@ -18,7 +18,7 @@ In addition, we are releasing an Admin API (in beta). The Admin API is a REST AP
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube.com/embed/OpPOaJI_Z28"
|
||||
src="https://www.youtube-nocookie.com/embed/OpPOaJI_Z28"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
@@ -151,3 +151,5 @@ The new API also opens the door to a whole new suite of integrations, including
|
||||
- [Open Source at Supabase - Founders Fireside Chat](https://www.youtube.com/watch?v=4t_63HT3rZY)
|
||||
- [Day 2 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
- [Day 3 - Supabase is SOC2 compliant](https://supabase.com/blog/supabase-soc2)
|
||||
- [Youtube video - Security Day](https://www.youtube.com/watch?v=6bGQotxisoY)
|
||||
@@ -312,7 +312,7 @@ We'll continuing merging security fixes to v1, with maintenance patches for the
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube.com/embed/iqZlPtl_b-I"
|
||||
src="https://www.youtube-nocookie.com/embed/iqZlPtl_b-I"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
@@ -323,12 +323,14 @@ We'll continuing merging security fixes to v1, with maintenance patches for the
|
||||
|
||||
- [v2 Release Candidate Documentation](https://supabase.com/docs/reference/javascript/next)
|
||||
- [Release Notes & Migration Guide](https://supabase.com/docs/reference/javascript/next/release-notes)
|
||||
|
||||
|
||||
## More Launch Week 5
|
||||
|
||||
- [Launch Week Page](https://supabase.com/launch-week)
|
||||
- [Launch Week 5 Hackathon](https://supabase.com/blog/launch-week-5-hackathon)
|
||||
- [Supabase Series B](https://supabase.com/blog/supabase-series-b)
|
||||
- [Open Source at Supabase - Founders Fireside Chat](https://www.youtube.com/watch?v=4t_63HT3rZY)
|
||||
- [Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [Day 1 - Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [Youtube video - Supabase CLI v1 and Admin API Beta](https://www.youtube.com/watch?v=OpPOaJI_Z28&feature=emb_title)
|
||||
- [Day 3 - Supabase is SOC2 compliant](https://supabase.com/blog/supabase-soc2)
|
||||
- [Youtube video - Security Day](https://www.youtube.com/watch?v=6bGQotxisoY)
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: 'Supabase is SOC2 compliant'
|
||||
description: Supabase is now SOC2 compliant. Learn how we got here and what it means for our customers.
|
||||
author: inian
|
||||
image: lw5-soc2/thumb.jpg
|
||||
thumb: lw5-soc2/thumb.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-17'
|
||||
toc_depth: 3
|
||||
---
|
||||
|
||||
Supabase is now SOC2 Type 1 compliant. Let’s dig into what that means, and explain the process we went through to get there. If you’re building a SaaS product, this blog post should provide a rough guide to getting your SOC2 certification.
|
||||
|
||||
## What is SOC2?
|
||||
|
||||
SOC2 is a compliance standard developed by the American Institute of CPAs. Yup CPAs - a bunch of accountants came up with the generally accepted compliance security standard for SaaS companies. SOC2 evaluates companies on 5 Trust Services Criteria: security, availability, processing integrity, confidentiality, and privacy. There are two types of compliance, both requiring an external audit:
|
||||
|
||||
- Type 1: checks if a company is compliant at a point in time.
|
||||
- Type 2: checks if a company stays compliant during an observation window (typically 6 months to a year).
|
||||
|
||||
## Why did we get SOC2 certified?
|
||||
|
||||
The main reason to go through a SOC2 audit is a simple one - customers expect it.
|
||||
|
||||
The Supabase team was spending a considerable amount of time filling out security questionnaires and fielding calls with potential customers - walking them through our security practices and how we protect customer data.
|
||||
|
||||
We are a database company — customers trust us with their data. We started with a SOC2 audit since one of the main things covered is our handling of sensitive customer data.
|
||||
|
||||
It is also much easier to become-and remain-SOC2 compliant when you institute the appropriate practices and standards as early as possible.
|
||||
|
||||
## Choosing a compliance monitoring tool
|
||||
|
||||
There are a few tools that plug into your cloud providers, task management system, identity, and HR providers and make it easy to monitor, collect and submit evidence to auditors. We evaluated [Vanta](https://www.vanta.com/), [Drata](https://drata.com/), [Secureframe](https://secureframe.com/), and [Tugboat Logic](https://tugboatlogic.com/). Our stack is pretty standard (AWS, GCP, GSuite, and Github). All the tools we evaluated were integrated with these systems.
|
||||
|
||||
Some of them had overly broad permissions when integrating with our vendors (read/write access to Github for example) which made them a no-go. Some came with a lightweight agent that we could use for Mobile Device Management (MDM). Other than that, the products are largely the same.
|
||||
|
||||
We chose Vanta, with Drata coming in a close second. Vanta supported more compliance standards (at that time) and is a fellow YC company (which sealed the deal). The gap between these tools is much closer now since all of them support the compliance standards we have our eyes on.
|
||||
|
||||
## Choosing an auditor
|
||||
|
||||
After setting up Vanta (nb: pestering devs to install a security agent on their laptop) and working through the checklist of tasks required for SOC2, we started looking around for auditors. Vanta was helpful here - they made introductions to a few auditors and we chose one who has previously worked with a lot of SaaS companies. Our auditors were also familiar with how Vanta worked which made the audit easier for us.
|
||||
|
||||
The engagement started with a call where we reviewed the systems which are in scope for the audit. We then set a date at which the audit takes place. The Type 1 audit verifies that we are adhering to our stated policies at this point in time.
|
||||
|
||||
## Off to the races
|
||||
|
||||
Once the date for the audit was set, it was a mad scramble to get everything in order.
|
||||
|
||||
Vanta has a lightweight, read-only agent built on top of [osquery](https://github.com/osquery/osquery) to verify if all team members have important security features enabled: hard disk encryption, screen locks, etc. It supports Mac, Windows, and Linux, although we had [some issues](https://github.com/system76/firmware-open/issues/268) with the agent running correctly in Linux. Getting hard disk encryption right is still difficult in some Linux distros. We decided to standardize on Mac and Windows to sidestep these issues. A more powerful MDM would enable us to remote wipe computers in case it is stolen, but we decided that the existing protections we had in place were sufficient to defend against this scenario.
|
||||
|
||||
We came up with a few important policies. For example, Access Control Policy, Data Management Policy, Asset Management Policy, etc. Vanta has templates which we used as a starting point and adapted to our requirements. Since our auditors are familiar with the Vanta templates, there wasn’t much back and forth regarding the policy language.
|
||||
|
||||
For employee background checks, we use [Certn](https://certn.co/). They integrate with Vanta, making it easy to check the status within the Vanta portal itself. Background checks aren’t _required_ for SOC2, but they are a factor in deciding whom we hire especially in certain roles like SRE and Finance where there is little room for error.
|
||||
|
||||
We submitted a ton of evidence to prove that we can stay on top of all activities in our cloud. We use [Vector](https://vector.dev/) to ship logs to [Logflare](http://logflare.com/), where they are retained at least for a year. Our [monitoring stack](https://supabase.com/blog/supabase-reports-and-metrics) consists of regional Victoria Metrics clusters and metrics are then aggregated into a centralized cluster. We also read from Cloudtrail logs and get notified in Slack when certain events like the root AWS account is logged into, a bucket is made public, an IAM policy changes, etc.
|
||||
|
||||
Enabling GitHub’s branch protection protects your repos from merging code without receiving a review first. This can be a challenge sometimes - at Supabase we have a few one-person teams. We had to relax our policy for some repos (POCs, internal projects) while keeping it strict for repos that handle critical systems.
|
||||
|
||||
Other tasks were already handled - encrypting data at rest and in transit, enforcing MFA where possible, standardizing on a password manager, and not using long-lived SSH keys (we use [AWS Instance Connect](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect.html)), etc.
|
||||
|
||||
We also evaluated all our vendors who had access to confidential data and now it was our turn to send them questionnaires or ask them for their SOC2 reports 😈.
|
||||
|
||||
## Making the SOC2 process work for you
|
||||
|
||||
We went through a lot of effort to make sure we weren’t adding processes just because it’s a requirement for SOC2. Everything had to improve our security or risk threshold in a meaningful way. This usually involves back and forth with the auditor to show how you satisfy a particular control even though you may not be doing it in exactly the way they want you to.
|
||||
|
||||
We used the SOC2 process to codify the security practices we were already doing informally at Supabase.
|
||||
|
||||
There are a few more debatable “check-the-box” activities - like the security awareness training which I couldn’t find a way around as much as I tried. Our team has a pretty good security posture and we don’t think watching a video on why reusing passwords is a bad idea helps much.
|
||||
|
||||
## A few surprises
|
||||
|
||||
We were surprised by the amount of manual evidence that we had to collect (umm..take screenshots) even with a tool like Vanta. There are things an automated tool like Vanta can never fully automate. For example, we had to collect evidence to show that have proper on-boarding and off-boarding checklists or demonstrate how we resolve security issues reported by our penetration tests within a certain time frame.
|
||||
|
||||
Since the Type 1 audit is just about providing evidence at a single point in time, there isn’t _that_ much utility in using a tool like Vanta. However, for Type 2 certification, where we need to show evidence that we have been compliant over a period of time, a monitoring tool like Vanta becomes more useful. Additionally, if you’re planning to get multiple certifications, investing in a compliance monitoring tool is valuable since there is considerable overlap between different frameworks, and you’ll only need to do the work of collecting your evidence once.
|
||||
|
||||
We spent some time trying to get a perfect score in Vanta before reaching out to the auditor. That turned out to be a mistake; Vanta is fairly broad in its checks, but the ones you need to pass depend on the audit’s scope, and the auditor. For example, our auditor didn’t care about seeing our exact board meeting minutes, but Vanta wanted us to document it!
|
||||
|
||||
Another revelation was that a lot of controls other companies had talked about in their SOC2 compliance journeys ended up not being a blocker for us. I am not going to list them here since it is dependent on the systems that are in scope, your larger architecture, and your auditor. Again, the takeaway here is to reach out to your auditor as early as possible to get a sense of what is relevant to your audit.
|
||||
|
||||
Auditors aren’t adversarial like pentesters or bug bounty hunters. For example, if you point them to a PR and say that PR closes a security issue reported, they _trust_ that it did. They aren’t going to find a way to bypass the fix you implemented and use that to raise an exception in your audit. This is why getting SOC2 certified is just a small part of staying secure - what makes your auditor happy will likely be pretty different from what makes a penetration tester happy.
|
||||
|
||||
## Security Center
|
||||
|
||||
Today we are launching our [security center](https://supabase.com/security), which shows the steps we take to protect your data. You can also find our audit reports at our security portal [here](https://security.supabase.com), or reach out to growth@supabase.com
|
||||
|
||||
## What’s next
|
||||
|
||||
Getting the Type 1 certification is just the start, and we will be working on getting certified for SOC2 Type 2 and HIPAA next. If you are interested in discussing these, we would love to chat. We will also be rolling out a series of security improvements to all projects hosted on the Supabase Cloud offering over the coming months. Stay tuned!
|
||||
|
||||
## Announcement video and discussion
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/6bGQotxisoY"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
## More Launch Week 5
|
||||
|
||||
- [Launch Week Page](https://supabase.com/launch-week)
|
||||
- [Launch Week 5 Hackathon](https://supabase.com/blog/launch-week-5-hackathon)
|
||||
- [Day 1 - Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [Youtube video - Supabase CLI v1 and Admin API Beta](https://www.youtube.com/watch?v=OpPOaJI_Z28&feature=emb_title)
|
||||
- [Day 2 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: 'Realtime: Multiplayer Edition'
|
||||
description: Announcing the general availability of Realtime's Broadcast and Presence.
|
||||
author: wenbo_xie,stas
|
||||
image: lw5-realtime/thumb.jpg
|
||||
thumb: lw5-realtime/thumb.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-18'
|
||||
toc_depth: 3
|
||||
---
|
||||
|
||||
During our last Launch Week, we teased our plans for "multiplayer" features. If you need a refresher,
|
||||
take a glance at [Supabase Realtime, with Multiplayer Features](https://supabase.com/blog/supabase-realtime-with-multiplayer-features)
|
||||
or go to [multiplayer.dev](https://multiplayer.dev) for an interactive demo.
|
||||
|
||||
Today, we're excited to announce the general availability of Realtime's multiplayer features, Broadcast and Presence.
|
||||
|
||||
## TLDR
|
||||
|
||||
Here are the key takeaways:
|
||||
|
||||
- We've added [Broadcast](https://supabase.com/docs/guides/realtime/broadcast) and [Presence](https://supabase.com/docs/guides/realtime/presence) to our Realtime server. You can use these features with the new [supabase-js](https://supabase.com/docs/reference/javascript/next) release.
|
||||
- All active Supabase projects on the free tier have access to the these features.
|
||||
- All new Supabase projects created from August 18th have access to these features.
|
||||
- We will work with all other projects to migrate to the new Realtime over the next few weeks. If you want immediate access, [reach out](https://app.supabase.com/support/new).
|
||||
- [Chris McCord](https://twitter.com/chris_mccord), the creator of Phoenix Framework, is now a technical advisor.
|
||||
|
||||
## Background
|
||||
|
||||
Before we discuss the new features, let's review what Realtime is and its significance to Supabase. Skip ahead if you just want to see the new features!
|
||||
|
||||
The first iteration of Realtime server was written by [@kiwicopple](https://twitter.com/kiwicopple), our CEO.
|
||||
At his previous startup, a chat application he built was facing performance issues while broadcasting database changes from Firestore to individual subscribers.
|
||||
|
||||
He turned to Postgres, which has two built-in pieces of functionality for emitting database changes:
|
||||
|
||||
- The first, Postgres's LISTEN/NOTIFY, seems like the obvious choice because it conveniently does what its name implies, listen for changes and notify subscribers. However, this approach has a hidden limitation - NOTIFY has a payload limit of 8,000 bytes. The workaround is to send only a unique identifier and then have the client query the database for the specific change. This would have been been too slow for the chat application.
|
||||
- The second, Postgres's logical replication, doesn't face the same limitations, and Paul used this approach. This required the introduction of a server to listen to a logical replication slot. Paul chose [Elixir](https://elixir-lang.org) and the [Phoenix Framework](https://www.phoenixframework.org) for the server as it scales exceptionally well, especially when dealing with WebSockets. He named this server "[Realtime](https://github.com/supabase/realtime)," leveraging other open source projects, [cainophile](https://github.com/cainophile/cainophile) and [pgoutput_decoder](https://github.com/cainophile/pgoutput_decoder), to listen to the replication stream and decode changes. From there, the changes were serialized into JSON and sent on their merry way to clients.
|
||||
|
||||
Realtime was the very first open source project of Supabase and played a pivotal role in our founding. Over time, we've improved both the performance and security.
|
||||
During Launch Week 3, we announced [Realtime RLS](https://supabase.com/blog/realtime-row-level-security-in-postgresql), which allows developers to tap into Postgres's Row Level Security to authorize changes before broadcasting them to clients. This enabled developers to use the same security framework across the entire Supabase stack.
|
||||
|
||||
## Realtime Channels
|
||||
|
||||
We've modified the architecture of Realtime to introduce two core features: Broadcast and Presence.
|
||||
|
||||
In this new version, everything is a [Channel](https://hexdocs.pm/phoenix/Phoenix.Channel.html). Channels are like “Rooms” where participants can join, and leave - very similar to Slack Channels or Discord Channels.
|
||||
|
||||
Broadcast and Presence are built into every Channel, and we've retro-fitted the Database change events into Channels too.
|
||||
|
||||
### Broadcast
|
||||
|
||||
Broadcast follows the classic Publisher/Subscriber pattern. A client (publisher) “broadcasts” messages using a unique identifier. For example, a user could send a message to a `#random` channel.
|
||||
|
||||
Other clients (subscribers) can “listen” to these messages in real-time, using the unique identifier. If they are listening to the `#random` channel, then they will receive the message.
|
||||
|
||||
This functionality is [baked into the Phoenix framework](https://hexdocs.pm/phoenix/Phoenix.Channel.html) and we've already been using this to [broadcast Postgres changes](https://supabase.com/docs/reference/javascript/subscribe).
|
||||
With this release we're exposing the underlying primitives which unlocks a variety of use-cases for developers.
|
||||
|
||||
A common use-case is sharing a user's cursor position with other clients in an online game. Previously, developers were sending all the mouse movements through their Postgres database which added latency and degraded database performance. In contrast, Broadcasts are ephemeral - they bypass the database completely.
|
||||
|
||||
### Presence
|
||||
|
||||
Presence synchronizes shared state between users. Presence is very similar to Broadcast, except that the state is “persisted” in the Channel so that new joiners immediately receive the state without waiting for another user to broadcast it. In our Slack example, when you turn on Slack you can see who's online without each individual user sending an “I'm online” message to the new-joiner.
|
||||
|
||||
Presence utilizes Broadcast as the transport layer, consolidating the state in an eventually-consistent and conflict-free manner. Users are free to come-and-go as they please, and as long as they are all subscribed to the same Channel then they will all have the same Presence state as each other.
|
||||
|
||||
The neat thing about Presence is that if a user is suddenly disconnected (for example, they go offline), their state will be automatically removed from the shared state.
|
||||
If you've ever tried to build an “I'm online” feature which handles unexpected disconnects, you'll appreciate how useful this is.
|
||||
|
||||
## Client Library
|
||||
|
||||
We've introduced new functionality into the [release candidate](https://supabase.com/blog/supabase-js-v2) version of `supabase-js`.
|
||||
|
||||
Here's a taste of how you can start using Broadcast and Presence and continue to listen to Postgres changes.
|
||||
|
||||
### Broadcast Example
|
||||
|
||||
In this example we'll send and receive mouse cursor positions to anyone in `room_1`.
|
||||
|
||||
```js
|
||||
const channel = supabase.channel('room_1')
|
||||
const MOUSE_EVENT = 'cursor'
|
||||
|
||||
// Subscribe to mouse events.
|
||||
// Our second parameter filters only for mouse events.
|
||||
channel
|
||||
.on(
|
||||
'broadcast',
|
||||
{ event: MOUSE_EVENT },
|
||||
(event) => { receivedCursorPosition(event) }
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
// Handle a mouse event.
|
||||
const receivedCursorPosition({ event, payload }) => {
|
||||
console.log(`
|
||||
User: ${payload.userId}
|
||||
x Position: ${payload.x}
|
||||
y Position: ${payload.y}
|
||||
`)
|
||||
}
|
||||
|
||||
// Helper function for sending our own mouse position.
|
||||
const sendMousePosition(channel, userId, x, y) => {
|
||||
return channel.send({
|
||||
type: 'broadcast',
|
||||
event: MOUSE_EVENT,
|
||||
payload: { userId, x, y }
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Presence Example
|
||||
|
||||
Let's create a contrived example where we could display a “user is typing” indicator.
|
||||
In this case, we'll send the timestamp for the last time that a user hit a key.
|
||||
Other clients can use this timestamp to display a “typing…” indicator.
|
||||
|
||||
```js
|
||||
const userId = 'user_1234'
|
||||
const slackRoomId = '#random'
|
||||
|
||||
const channel = supabase.channel(slackRoomId, {
|
||||
config: {
|
||||
presence: { key: userId }
|
||||
}
|
||||
})
|
||||
|
||||
// We can subscribe to all Presence changes using the 'presence' -> 'sync' event.
|
||||
channel
|
||||
.on('presence', { event: 'sync' }, () => presenceChanged())
|
||||
.subscribe()
|
||||
|
||||
/*
|
||||
A contrived example where we bind to all keyboard
|
||||
events and send them over our channel
|
||||
*/
|
||||
document.addEventListener('keydown', function(event){
|
||||
channel.track({ isTyping: Date.now() })
|
||||
})
|
||||
|
||||
// Receive Presence updates
|
||||
const presenceChanged = () => {
|
||||
const newState = channel.presenceState()
|
||||
console.log(newState)
|
||||
}
|
||||
|
||||
// When you no longer wish to track data
|
||||
channel.untrack().then(status => console.log(status)
|
||||
```
|
||||
|
||||
### Receiving Postgres Changes
|
||||
|
||||
You can receive Postgres changes on any channel. For this example, we'll receive all messages on the `#random` channel.
|
||||
|
||||
```js
|
||||
const channelId = '#random'
|
||||
|
||||
// Create a filter only for new messages
|
||||
const databaseFilter = {
|
||||
schema: 'public',
|
||||
table: 'messages',
|
||||
filter: `room_id=eq.${channelId}`,
|
||||
event: 'INSERT',
|
||||
}
|
||||
|
||||
const channel = supabase
|
||||
.channel(channelId)
|
||||
.on('postgres_changes', databaseFilter, (payload) => receivedDatabaseEvent(payload))
|
||||
.subscribe()
|
||||
|
||||
const receivedDatabaseEvent = (event) => {
|
||||
const { payload } = event
|
||||
console.log(payload)
|
||||
}
|
||||
```
|
||||
|
||||
## Future Plans
|
||||
|
||||
This is a big change, but it's only a small step towards the final goal. We have a few exciting plans for the future.
|
||||
|
||||
### Extensions
|
||||
|
||||
Our `postgres_changes` listener is the first of many [Extensions](https://supabase.com/blog/supabase-realtime-with-multiplayer-features#extensions).
|
||||
We've had requests add other integrations beyond Postgres:
|
||||
|
||||
- **Finance:** Listen to stock market events and broadcast them to connected users
|
||||
- **Web3:** Listen to blockchain events and broadcast them to connected users
|
||||
- **Authoritative clocks:** A server clock which broadcasts a timer (e.g. auction sites or ticketing systems)
|
||||
|
||||
### Peer to Peer
|
||||
|
||||
A lot of users ask about using Realtime for peer to peer applications. We plan to use Realtime as a WebRTC signaling server which will enable developers to build collaborative software with even lower latency. A common example we've seen is collaborative code editors with a CRDT implementation, like Yjs.
|
||||
|
||||
### Realtime Inspector
|
||||
|
||||
We're building a Realtime inspector into the Supabase Dashboard so it'll be easier to debug the messages that are getting passed through your Channels.
|
||||
|
||||
## Technical Overview
|
||||
|
||||
Before this release, every Supabase project had a server running Realtime with the other Supabase services like Kong, GoTrue, and PostgREST.
|
||||
|
||||
In this release we take advantage of Elixir's strengths by running a distributed cluster of servers across the world. Each server communicates directly with the other nodes in the cluster. This improves performance by balancing the load across nodes.
|
||||
|
||||
Clients connect to the nearest node in the cluster, and we take advantage of the cluster's fast backbone network to improve client connection speeds, stability, and latency. This is especially useful for clients in regions with variable internet quality.
|
||||
|
||||
The entire cluster runs on [Fly](https://fly.io/) - we're big fans!
|
||||
|
||||
Much of the new functionality leverages the [Phoenix Framework](https://www.phoenixframework.org/). This makes it relatively straightforward to offer Broadcast ([Phoenix PubSub](https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html)) and Presence ([Phoenix Presence](https://hexdocs.pm/phoenix/Phoenix.Presence.html)) in a globally-distributed cluster. Presence is built on top of [Phoenix Tracker](https://hexdocs.pm/phoenix_pubsub/Phoenix.Tracker.html), a delta-based conflict-free replicated data type (CRDT) for eventually consistent and conflict-free synced state.
|
||||
|
||||
In the future, we'll document the challenges we faced migrating to this new architecture as well as a few challenges we expect to face in the future.
|
||||
|
||||
## One More Thing
|
||||
|
||||
We have some great news! [Chris McCord](https://twitter.com/chris_mccord), the creator of the Phoenix framework, has agreed to become a Technical Advisor for Supabase.
|
||||
|
||||
Chris works at Fly, and will continue to work there. His role as an advisor is mostly to express our gratitude for the work he's already done (admittedly, we'll probably need his advice for some upcoming challenges). Realtime is made possible by his open source work.
|
||||
|
||||
We also want to thank [José Valim](https://twitter.com/josevalim), and everyone in the Erlang/Elixir ecosystem, for your open source contributions that have made our lives here on the Supabase Realtime team a lot easier.
|
||||
|
||||
## Announcement video and discussion
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/CGZr5tybW18"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
## More Launch Week 5
|
||||
|
||||
- [Launch Week Page](https://supabase.com/launch-week)
|
||||
- [Launch Week 5 Hackathon](https://supabase.com/blog/launch-week-5-hackathon)
|
||||
- [Day 1 - Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [Youtube video - Supabase CLI v1 and Admin API Beta](https://www.youtube.com/watch?v=OpPOaJI_Z28&feature=emb_title)
|
||||
- [Day 2 - supabase-js v2 Release Candidate](https://supabase.com/blog/supabase-js-v2)
|
||||
- [Youtube Video - supabase-js v2 Release Candidate](https://www.youtube.com/watch?v=iqZlPtl_b-I)
|
||||
@@ -0,0 +1,288 @@
|
||||
---
|
||||
title: 'Community Day'
|
||||
description: Wrapping up Launch Week 5 with contributors, partners, and friends.
|
||||
author: andrew_smith,jonmeyers_io,thor_schaeff,tyler_shukert
|
||||
image: lw5-community-day/community_day_og.jpg
|
||||
thumb: lw5-community-day/community_day_og.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
- community
|
||||
date: '2022-08-19'
|
||||
toc_depth: 2
|
||||
---
|
||||
|
||||
Supabase combines existing open-source tools with our own open-source contributions to provide a delightful experience for developers of all skill levels. Just as versatile as our platform, we're building a community of communities, bringing together developers from many different backgrounds, as well as new developers looking to get involved with open source.
|
||||
|
||||
To wrap up Launch Week 5, we're showcasing some of the communities and contributors that make up the Supabase community, highlighting their awesome work, and celebrating everyone who contributes their time to the Supabase mission. 💚
|
||||
|
||||
---
|
||||
|
||||
## Launch Week 5 - a new era?!
|
||||
|
||||
If you're an avid Launch Week participant, you might have been surprised this time because we usually kick-off with Community Day on Mondays.
|
||||
And we previously closed Launch Week with a bunch more things on Friday, and the start of our virtual Hackathon.
|
||||
|
||||
This time, we're switching things around:
|
||||
|
||||
- [Monday to Thursday](/launch-week) are the big-ticket launches.
|
||||
- Friday, we highlight all the additional “one more thing(s)” that we've launched, as well as shine a light on our awesome community contributions.
|
||||
- As you [might have noticed](/blog/launch-week-5-hackathon), we now run our virtual Hackathon throughout Launch Week, and as always you can win some awesome limited edition swag, and for the first time ever, there's a $1500 GitHub sponsorship awarded to the best overall project!
|
||||
|
||||
<blockquote class="twitter-tweet" data-theme="dark">
|
||||
<p lang="en" dir="ltr">
|
||||
Thanks to <a href="https://twitter.com/supabase?ref_src=twsrc%5Etfw">@supabase</a> for this
|
||||
little beauty (the hat, not the cat).
|
||||
<br />
|
||||
<br />
|
||||
Now I've just got to pry it away from Peanut 🥜 😂 <a href="https://t.co/POBdVZrF5N">
|
||||
pic.twitter.com/POBdVZrF5N
|
||||
</a>
|
||||
</p>
|
||||
— Daniel Cranney 🇬🇧 (@danielcranney) <a href="https://twitter.com/danielcranney/status/1557249589182447616?ref_src=twsrc%5Etfw">August 10, 2022</a>
|
||||
</blockquote>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
_Our limited edition swag is approved by professional swag testers like Peanut!_
|
||||
|
||||
### Launch Week Landing Page & Golden Tickets
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/4_duDgQeCyM?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
We now have a shiny new [Launch Week page](http://supabase.com/launch-week), your one-stop shop for all things Launch Week, where you can find each day's feature as well as highlights from the past Launch Weeks.
|
||||
|
||||
We've taken a page out of [Vercel's Virtual Events Starter Kit](https://vercel.com/templates/next.js/virtual-event-starter-kit), and generated over 3000 virtual tickets. Thank you all for participating, we love [seeing your tickets on Twitter](https://twitter.com/hashtag/SupaLaunchWeek?src=hashtag_click&f=live)! To make this work, we've adapted the Virtual Events Starter Kit and [added in a Supabase Database provider](https://github.com/vercel/virtual-event-starter-kit/pull/88) as an alternative to the Redis database option.
|
||||
|
||||
We've added a Golden Ticket mechanic, distributing some special edition launch week swag to some lucky winners. If you're interested in how we've built this, check out the video above with a brief explanation.
|
||||
|
||||
---
|
||||
|
||||
## Open Source Spotlight
|
||||
|
||||
### pg_jsonschema
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/4A6RKPp1b70?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
For our Open Source Spotlight we're hearing from [Dmitry Dygalo](https://twitter.com/Stranger6667) from [schemathesis.io](https://schemathesis.io/) who works on a multitude of open-source projects.
|
||||
He's the author and maintainer of [jsonschema-rs](https://github.com/Stranger6667/jsonschema-rs),
|
||||
which is the foundation for our new [pg_jsonschema extension](https://github.com/supabase/pg_jsonschema), a PostgreSQL extension providing JSON Schema validation.
|
||||
|
||||
[Learn about pg_jsonschema](/blog/pg-jsonschema-a-postgres-extension-for-json-validation).
|
||||
|
||||
### Postgrest v10
|
||||
|
||||

|
||||
|
||||
Today, PostgREST v10 was [released](https://github.com/PostgREST/postgrest/releases/tag/v10.0.0).
|
||||
In this [blog post](/blog/postgrest-v10) we explore some of its new features: EXPLAIN and Improved Relationship Detection.
|
||||
|
||||
[Read the blog post](/blog/postgrest-v10).
|
||||
|
||||
---
|
||||
|
||||
## New courses & tutorials
|
||||
|
||||
### Free Egghead course: Cache Supabase data at the Edge with Cloudflare Workers and KV Storage
|
||||
|
||||
[](https://egghead.io/courses/cache-supabase-data-at-the-edge-with-cloudflare-workers-and-kv-storage-883c7959)
|
||||
|
||||
Caching is one of the hardest problems in Computer Science!
|
||||
|
||||
Unless you pair Supabase with Cloudflare, then it is actually quite simple!
|
||||
|
||||
Check out [Jon Meyer's](https://twitter.com/jonmeyers_io), entirely free egghead course — Cache Supabase data at the Edge with Cloudflare Workers and KV Storage — dropping right now!
|
||||
|
||||
Learn how to:
|
||||
|
||||
- Use Wrangler CLI to interface with Cloudflare
|
||||
- Proxy Supabase requests through Cloudflare Workers
|
||||
- Bind a KV Store to cache data
|
||||
- Cache response data from Supabase
|
||||
- Automatically revalidate cache when data changes
|
||||
- Continue performing work after a response has been sent
|
||||
|
||||
All that in only 28 mins — or 14 mins on 2x speed!
|
||||
|
||||
### Realtime Trello Board with Angular by Simon Grimm
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/shv7uT_NM7Y?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
[Simon Grimm](https://twitter.com/schlimmson) from [ionicacademy.com](http://ionicacademy.com/) & [devdactic.com](http://devdactic.com/) is releasing a new course for all the Angular fans out there!
|
||||
|
||||
- [Subscribe](https://www.youtube.com/simongrimmdev_) to Simon's YouTube where the course will be released soon!
|
||||
- Find the code on GitHub: [github.com/saimon24/supabase-trello-angular](https://github.com/saimon24/supabase-trello-angular)
|
||||
|
||||
---
|
||||
|
||||
## Integrations, Expert Partners, and Developer Stories
|
||||
|
||||
Since releasing our [Partners](/partners) page last Launch Week, we've had a lot of new partners reach out to join the community.
|
||||
|
||||
### CodeSandbox Projects Beta
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/cTNUjAQ06AE?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
The new [CodeSandbox Projects Beta](https://projects.codesandbox.io/) let's you run your projects and turn them into a link you can share with anyone. Developers visiting your link can not only see your running code, they can click “fork” and get an exact copy of that environment so they can easily contribute back to your masterpiece. CodeSandbox integrates directly with GitHub, so you get a unique development environment for every PR you and your contributors open!
|
||||
|
||||
You can do all of this from a web browser, from [within VSCode](https://marketplace.visualstudio.com/items?itemName=CodeSandbox-io.codesandbox-projects), or via the [native iPad app](https://apps.apple.com/us/app/codesandbox/id1423330822)! Give it a try with the [Supabase example project](https://codesandbox.io/p/github/codesandbox/codesandbox-supabase-example/main?file=%2FREADME.md)!
|
||||
|
||||
### Dashibase
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/WAYA6-qBfPs?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
[Dashibase](https://dashibase.com/) is a no-code internal tools builder with a Notion-like UI. With the latest update, you can easily build CRUD dashboards on top of your Supabase projects, set read/write access on your data sources, and share your dashboards with your team. Stop building dashboards from scratch.
|
||||
|
||||
### Replicache
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/0lBxH6d38FM?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
Replicache is a JavaScript framework for building high performance, collaborative, offline-first web apps.
|
||||
|
||||
It's inspired by apps like [Linear](https://linear.app/) and [Superhuman](https://superhuman.com/). When the user takes an action in one of these apps, it happens instantly, with no server round-trip, and changes from other users appear in realtime.
|
||||
|
||||
Replicache works with Supabase for storage, and Supabase Realtime for its [poke message feature](https://doc.replicache.dev/how-it-works#poke-optional). Read [the guide](https://doc.replicache.dev/deploy-vercel-supabase) to learn how to [deploy to Vercel and Supabase](https://doc.replicache.dev/deploy-vercel-supabase)!
|
||||
|
||||
### [Zapp.run](http://Zapp.run) by Invertase
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/ctSlcU2i9WA?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
Zapp is a free online sandbox environment for building Flutter applications in the browser. With Zapp, you can enjoy building Flutter apps as though in your favorite IDE, especially if you are a VSCode user; you should feel at home.
|
||||
|
||||
You can install any pub packages and start developing, of course including Supabase! You can sign up for our early access program [here](https://www.notion.so/Social-media-strategy-1f06ed5695fe497ba6782a5ce007b04f)!
|
||||
|
||||
### Feelantera
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/Am9egV4Hgi4?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
Feelantera is a creative digital agency based in Indonesia. They craft web applications with cutting-edge technology, and are one of our new [Supabase Experts](https://supabase.com/partners/experts). They [recently open-sourced](https://twitter.com/feelantera/status/1556909234478059521) their Supabase Edge Functions powered URL shortener on [GitHub](https://github.com/feelantera/fltr-link).
|
||||
|
||||
If you're building with Supabase and are looking for some support, check out their [Expert listing](https://supabase.com/partners/feelantera) and reach out to them.
|
||||
|
||||
Are you also experienced in building with Supabase and interested in helping others? Apply to [become and Expert Partner](https://supabase.com/partners/experts#become-a-partner)!
|
||||
|
||||
### Snappify
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/rg1RMiv6uuc?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
snappify is a powerful design tool that helps you to explain and share your code snippets in many beautiful ways.
|
||||
|
||||
The editor lets you operate on a free canvas where you can arrange multiple code snippets and annotate them with arrow and text elements to explain specific parts of your code. You can style everything to your own needs and give your code presentations a personal touch by adding your social media branding.
|
||||
|
||||
Head over to [snappify.io](https://t.co/hdO3oY38If) and give it a try on your own - all the basic features are available for free.
|
||||
|
||||
### WalletConnect Cloud: You Can Now Sign In with Ethereum
|
||||
|
||||

|
||||
|
||||
[WalletConnect](https://walletconnect.com/) is an open source protocol for connecting decentralised applications to mobile wallets with QR code scanning or deep linking. This week they have launched the option for users to sign-in to their cloud platform with Ethereum. They are building this on top of GoTrue with the aim to contribute it back to our GoTrue fork to make it available to all Supabase users. If you're interested in this, you can follow the [PR here](https://github.com/supabase/gotrue/pull/282).
|
||||
|
||||
To explore the infrastructure backing the project, check out the repository [here](https://github.com/walletconnect/CloudSIWE). To try it out, create an account on the WalletConnect [cloud platform](https://cloud.walletconnect.com/). To read more about the feature, head on over to the [WalletConnect blog](https://medium.com/walletconnect/walletconnect-cloud-you-can-now-sign-in-with-ethereum-7563578686c2).
|
||||
|
||||
## Hackathon
|
||||
|
||||
<iframe
|
||||
className="w-full"
|
||||
width="560"
|
||||
height="315"
|
||||
src="https://www.youtube-nocookie.com/embed/rI3Ik7GyYEw?modestbranding=1&autohide=1&showinfo=0&controls=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
We hope all of these awesome projects and stories gave you plenty of inspiration and you're ready to build in a weekend and scale to millions, as our [hackathon is still running until Sunday](https://supabase.com/blog/launch-week-5-hackathon) night PT!
|
||||
|
||||
---
|
||||
|
||||
## Oh - and one more thing!
|
||||
|
||||
Well, actually a couple more things! As it is now tradition, we have too many things for one week, so at the end of the week we compile everything that didn't get its own spotlight day, into a nice little [box of treats](/blog/launch-week-5-one-more-thing).
|
||||
|
||||
---
|
||||
|
||||
## That's a wrap
|
||||
|
||||
Here we are. What a week indeed! Launch Week 5 was so much fun, thank you for participating and sharing what you're working on, and most importantly thank you for building with Supabase! 💚
|
||||
|
||||
We'll be jumping into our own hackathon projects now, and we'll see you next week for the highlight reel and the hackathon winner announcements, so make sure to subscribe on [Twitter](https://twitter.com/Supabase), and [YouTube](https://www.youtube.com/supabase) to not miss out! And do come hang out and hack together in [Discord](https://discord.supabase.com/)! See you there 👁️⚡️👁
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: 'One more thing'
|
||||
description: "Let's be honest, it's never just one more thing."
|
||||
author: paul_copplestone
|
||||
image: lw5-one-more/lw5-one-more-thumb.jpg
|
||||
thumb: lw5-one-more/lw5-one-more-thumb.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-19'
|
||||
toc_depth: 2
|
||||
---
|
||||
|
||||
Let's be honest, it's never just one more thing.
|
||||
Here are six more things that you need to know this Launch Week.
|
||||
|
||||
---
|
||||
|
||||
## Supabase Vault
|
||||
|
||||

|
||||
|
||||
Today we're announcing [Supabase Vault](/blog/supabase-vault), a Postgres extension for managing secrets and encryption inside your database.
|
||||
Vault is a thin usability-layer on top of [pgsodium](https://github.com/michelp/pgsodium).
|
||||
|
||||
Vault is not available on the Supabase Platform yet. This release is intended to gather user feedback.
|
||||
|
||||
[Read more](/blog/supabase-vault).
|
||||
|
||||
---
|
||||
|
||||
## Auth UI
|
||||
|
||||
<video width="99%" muted playsInline controls="true" autoplay="true">
|
||||
<source
|
||||
src="/images/blog/lw5-one-more/auth-ui-demo.mp4"
|
||||
type="video/mp4"
|
||||
muted
|
||||
playsInline
|
||||
autoplay
|
||||
/>
|
||||
</video>
|
||||
|
||||
Auth UI was previously released as a single `<Auth/>` component in the [`@supabase/ui`](http://github.com/supabase/ui) library.
|
||||
We recognized it was one of the most popular aspects of the library and developers were installing the library to use the Auth component alone.
|
||||
|
||||
From today, you can install it [from its own NPM package](https://github.com/supabase-community/auth-ui):
|
||||
|
||||
```bash
|
||||
npm install @supabase/auth-ui-react
|
||||
```
|
||||
|
||||
We've decoupled this library from our own styling system and you are now able to (_deep breath..._): create your own theme, use a pre-existing Supabase theme, extend a theme using token variables, create multiple variations of themes (and then also extend them with variables), use CSS classes and also use any inline CSS styles.
|
||||
|
||||
This is all done with [stitches.js](https://stitches.dev) (or more specifically, the [framework agnostic API](https://stitches.dev/docs/framework-agnostic)) to handle variants of components and the CSS properties.
|
||||
|
||||
A new feature in Auth UI is custom labels. You can now override any of the text labels—very useful for multiple language support.
|
||||
|
||||
Our initial release supports React, but we have prepared the repo for other frameworks. This release is a small step towards a larger feature—“_Hosted Auth Pages_”. The wide range of customization will become useful for developers to tweak their Hosted Auth pages to reflect their brand personality.
|
||||
|
||||
[View the docs](/docs/guides/auth/auth-helpers/auth-ui-overview).
|
||||
|
||||
---
|
||||
|
||||
## Dashboard permissions
|
||||
|
||||

|
||||
|
||||
We've released granular permissions for the Supabase Dashboard. Dashboard permissions allow you assign roles to your team and to restrict what they can do.
|
||||
|
||||
We're starting with 3 roles—Owner, Administrator, and Developer—which you can edit in the Org settings of the Dashboard.
|
||||
There's a tooltip in the header of the members table, which elaborates on the individual permissions available for each role.
|
||||
|
||||
[Read more](/docs/guides/hosting/platform#manage-team-members).
|
||||
|
||||
---
|
||||
|
||||
## JSON schema validation
|
||||
|
||||

|
||||
|
||||
We've released [`pg_jsonschema`](https://github.com/supabase/pg_jsonschema), a new Postgres extension for the Supabase Platform.
|
||||
|
||||
`pg_jsonschema` adds support for [JSON Schema](https://json-schema.org/) validation for `json` and `jsonb` data types, built with Rust.
|
||||
You can read the blog post, which explains some of the scenarios where this is useful.
|
||||
|
||||
[Read more](/blog/pg-jsonschema-a-postgres-extension-for-json-validation).
|
||||
|
||||
---
|
||||
|
||||
## pg_graphql v0.4.0
|
||||
|
||||

|
||||
|
||||
We've released a new version of `pg_graphql`, our GraphQL extension for Postgres.
|
||||
This release adds support for `json` / `jsonb` types, the `in` filter, and introspection for much larger schemas (10x larger than before). We've fixed a few bugs too.
|
||||
|
||||
You can read the [release notes](https://github.com/supabase/pg_graphql/releases/tag/v0.4.0) and [documentation](https://supabase.github.io/pg_graphql/), and start using `pg_graphql` on Supabase today.
|
||||
|
||||
[Read more](/blog/graphql-now-available).
|
||||
|
||||
---
|
||||
|
||||
## Multi-Factor Authentication
|
||||
|
||||

|
||||
|
||||
We've opened early-access signups for Multi-Factor Authentication (MFA). To be clear—this is for MFA for [Supabase Auth](/auth),
|
||||
which you can use to build additional layers of security in your applications (and not MFA for our Dashboard, which we will also release soon).
|
||||
|
||||
If you're interested, sign up and we'll grant your projects early access to the MFA API endpoints.
|
||||
|
||||
[Sign up](https://airtable.com/shrjcc9zi0RduHLIx).
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
title: 'pg_jsonschema: JSON Schema support for Postgres'
|
||||
description: "Today we're releasing pg_jsonschema, a Postgres extension for JSON validation."
|
||||
author: oli_rice
|
||||
image: lw5-pg_jsonschema/jsonschema-thumb.jpg
|
||||
thumb: lw5-pg_jsonschema/jsonschema-thumb.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-19'
|
||||
toc_depth: 3
|
||||
---
|
||||
|
||||
Released on the Supabase platform today, [pg_jsonschema](https://github.com/supabase/pg_jsonschema) is a Postgres extension
|
||||
which adds [JSON Schema](https://json-schema.org/) validation support for `json` and `jsonb` data types.
|
||||
|
||||
## The use-case for JSON validation
|
||||
|
||||
Despite Supabase being an SQL shop, even our most zealous relational data model advocates (begrudgingly) recognize some advantages to the document data model.
|
||||
Mainly, if some complex data will always be consumed together, a document data type can be a good fit.
|
||||
|
||||
**For Example**:
|
||||
|
||||
If our application receives data via a webhook:
|
||||
|
||||
```json
|
||||
{
|
||||
"status_code": 200,
|
||||
"checksum": "89b623f6332d2b9b42b4e17eaf1bcc60"
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Last-Modified": "Tue, 09 Aug 2022 09:14:10 GMT"
|
||||
},
|
||||
"payload": {
|
||||
{
|
||||
"sucess": true,
|
||||
"content": {
|
||||
"account_id": "d928b484-16bd-4f10-a827-3eb959b4cc14",
|
||||
"event": "SUBSCRIBED",
|
||||
"subscriptions": [
|
||||
{"subscription_id": 481, "exp": 1660050940},
|
||||
{"subscription_id": 121, "exp": 1660041852},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A reasonable swing at normalizing that data into tables might look like this:
|
||||
|
||||

|
||||
|
||||
That's a lot of architecting! Moreover, the query to recover the original input requires 5 joins!
|
||||
|
||||
A solution that aligns better with our intent would be to persist whatever we receive from the external service so long as it meets a minimum set of requirements.
|
||||
With Postgres' `json` data type we can achieve half of that goal.
|
||||
|
||||

|
||||
|
||||
Treating the webhook contents as a `json` document simplifies our data model. It is also robust to changing payloads and more efficient to query, update, and delete.
|
||||
|
||||
Now what about this part?
|
||||
|
||||
> so long as it meets a minimum set of requirements
|
||||
|
||||
## Challenges
|
||||
|
||||
The flexibility of document types also comes with some downsides.
|
||||
|
||||
The schema of the json payload from the previous example is a little intense for a blog post, so let's instead say we intend for a table's `json` column to hold objects with a `string` attribute named `foo` and no additional attributes.
|
||||
|
||||
Without constraints, the setup would be:
|
||||
|
||||
```sql
|
||||
create table some_table (
|
||||
id serial primary key,
|
||||
metadata json not null
|
||||
);
|
||||
|
||||
insert into some_table (metadata)
|
||||
values (<SQL Input>);
|
||||
|
||||
```
|
||||
|
||||
But the resulting schema is much more permissive than our intent. When inserting a mix of correct and incorrect values:
|
||||
|
||||

|
||||
|
||||
Only 2 of our 8 test cases were handled appropriately by our data model.
|
||||
|
||||
A core strength of SQL databases is their ability to constrain data's [types](https://www.postgresql.org/docs/current/datatype.html), nullability,
|
||||
[referential integrity](https://www.postgresql.org/docs/current/tutorial-fk.html), [uniqueness](https://www.postgresql.org/docs/current/ddl-constraints.html),
|
||||
and even [arbitrary developer-defined rules](https://www.postgresql.org/docs/current/sql-createtrigger.html).
|
||||
Those constraints are a lot to sacrifice to gain the convenience of document types.
|
||||
|
||||
Fortunately, the challenge of validating `json` documents isn't specific to SQL databases. NoSQL/Document databases, like MongoDB,
|
||||
[optionally enforce data constraints](https://www.mongodb.com/docs/atlas/app-services/schemas/) so there's plenty of prior art for us to draw from.
|
||||
|
||||
## JSON Schema
|
||||
|
||||
[JSON Schema](https://json-schema.org/) is a specification for validating the shape and contents of `json` documents.
|
||||
It can describe constraints for documents similar to those applied by relational databases.
|
||||
|
||||
Translating our constraints from the previous example into a JSON Schema we get:
|
||||
|
||||
```js
|
||||
// objects with a string attribute
|
||||
// named foo and no additional attributes
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["foo"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
```
|
||||
|
||||
Which is a formal and human-readable description of our intent. A tutorial on the JSON Schema language is out-of-scope
|
||||
for this article but you can find a full introduction in [their guide](https://json-schema.org/understanding-json-schema/index.html).
|
||||
|
||||
So now we have:
|
||||
|
||||
✅ flexible document data type → `json`
|
||||
|
||||
✅ a language to describe constraints on `json` documents → JSON Schema
|
||||
|
||||
❌ a way to enforce JSON Schema constraints on `json` documents in Postgres
|
||||
|
||||
## pg_jsonschema
|
||||
|
||||
[pg_jsonschema](https://github.com/supabase/pg_jsonschema) is a Postgres extension that can validate `json` and `jsonb` data types
|
||||
against a [JSON Schema](https://json-schema.org/). The extension offers two functions:
|
||||
|
||||
```sql
|
||||
-- Validates a json *instance* against a JSON Schema *schema*
|
||||
json_matches_schema(schema json, instance json) returns bool
|
||||
|
||||
-- Validates a jsonb *instance* against a JSON Schema *schema*
|
||||
jsonb_matches_schema(schema json, instance jsonb) returns bool
|
||||
```
|
||||
|
||||
We can use those functions in combination with a [check constraint](https://www.postgresql.org/docs/current/ddl-constraints.html) to more completely describe our data model.
|
||||
|
||||
```sql
|
||||
create table some_table(
|
||||
id serial primary key,
|
||||
metadata json not null,
|
||||
|
||||
check (
|
||||
json_matches_schema(
|
||||
schema :='{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["foo"],
|
||||
"additionalProperties": false
|
||||
}',
|
||||
instance := metadata
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
insert into some_table(metadata)
|
||||
values
|
||||
(<SQL input>);
|
||||
|
||||
```
|
||||
|
||||
With that check constraint in place, we re-run the same test cases:
|
||||
|
||||

|
||||
|
||||
Now all 8 tests are handled correctly. In cases where records failed to insert, Postgres throws an error referencing the failing constraint.
|
||||
|
||||
> ERROR: new row for relation "some_table" violates check constraint "some_table_metadata_check"
|
||||
>
|
||||
> DETAIL: Failing row contains (1, null).
|
||||
>
|
||||
> SQL state: 23514
|
||||
|
||||
With these tools you can wield the flexibility of `json`/`jsonb` data types without sacrificing the guarantees of a well specified data model!
|
||||
|
||||
To get started with `pg_jsonschema`, fire up a new supabase project and enable the extension with
|
||||
|
||||
```sql
|
||||
create extension pg_jsonschema;
|
||||
```
|
||||
|
||||
or follow the [Docker Compose instructions](https://github.com/supabase/pg_jsonschema#try-it-out) in the [repo's README](https://github.com/supabase/pg_jsonschema/blob/master/README.md).
|
||||
@@ -0,0 +1,282 @@
|
||||
---
|
||||
title: 'PostgREST v10: EXPLAIN and Improved Relationship Detection'
|
||||
description: "Today, PostgREST 10 was released. Let's take a look at some of the new features that go hand in hand with supabase-js v2."
|
||||
author: steve_chavez
|
||||
image: lw5/postgrest-v10.png
|
||||
thumb: lw5/postgrest-v10.png
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-19'
|
||||
toc_depth: 3
|
||||
---
|
||||
|
||||
PostgREST turns your PostgreSQL database automatically into a RESTful API. Today, PostgREST v10 was [released](https://github.com/PostgREST/postgrest/releases/tag/v10.0.0). v10 is not available on the Supabase Platform yet, but it is available for [self-hosting](https://supabase.com/docs/guides/hosting/overview) or as a executable binary from the GitHub release page.
|
||||
|
||||
Let's take a look at some of its new features that go hand in hand with [supabase-js v2](https://supabase.com/blog/supabase-js-v2).
|
||||
|
||||
## EXPLAIN
|
||||
|
||||
Akin to the [PostgreSQL EXPLAIN](https://www.postgresql.org/docs/current/sql-explain.html) command, you can now get the execution plan of a request through HTTP or `supabase-js`. This works transparently for reads, writes and RPC because every request to PostgREST generates a single SQL query.
|
||||
|
||||
This is only suitable for development environments and is only enabled when the `db-plan-enabled` config is set to `true`.
|
||||
|
||||
### Getting the execution plan through HTTP
|
||||
|
||||
Using `curl`, you can obtain the execution plan by specifying a vendor media type on the `Accept` header.
|
||||
|
||||
```bash
|
||||
$ curl -H 'Accept: application/vnd.pgrst.plan' \
|
||||
'https://<project>.supabase.co/clients?select=*&id=eq.1'
|
||||
|
||||
Aggregate (cost=8.18..8.20 rows=1 width=112)
|
||||
-> Index Scan using clients_pkey on clients (cost=0.15..8.17 rows=1 width=36)
|
||||
Index Cond: (id = 1)
|
||||
```
|
||||
|
||||
The `text` format is used by default, which gives you the same output you’d get in other SQL clients like `psql`. You can change the format to JSON by using a media type suffix `application/vnd.pgrst.plan+json`.
|
||||
|
||||
### Explaining supabase-js queries
|
||||
|
||||
For `supabase-js`, you can get the execution plan using the `explain()` transform. This works for every `supabase-js` method, including `rpc()`. Here’s an example for `select()`.
|
||||
|
||||
```jsx
|
||||
const { data, error } = await supabase
|
||||
.from('projects')
|
||||
.select('*')
|
||||
.eq('id', 1)
|
||||
.explain()
|
||||
|
||||
console.log(data)
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
Aggregate (cost=8.18..8.20 rows=1 width=112)
|
||||
-> Index Scan using projects_pkey on projects (cost=0.15..8.17 rows=1 width=40)
|
||||
Index Cond: (id = 1)
|
||||
```
|
||||
|
||||
Explaining the plan output in detail is beyond the scope of this blog post but basically it’s a tree of operations that PostgreSQL will follow for executing a query. Here we see the “Aggregate” node which corresponds to the `json_agg` function used by the PostgREST generated query(more details on how to find these later) and the “Index Scan” node which means an index on “id” was used for a fast search.
|
||||
|
||||
### Explaining RLS policies
|
||||
|
||||
The raison d'etre of `explain()` is to provide quicker feedback on the performance of queries, especially in the presence of RLS policies. For instance, let’s say we have this basic policy:
|
||||
|
||||
```sql
|
||||
create policy "anon can't read"
|
||||
on projects for select to anon
|
||||
using (
|
||||
false
|
||||
);
|
||||
```
|
||||
|
||||
And we use `explain()` again, this time with the `analyze` option(executes the query, same as the EXPLAIN ANALYZE counterpart in SQL) so we can see the execution time.
|
||||
|
||||
```jsx
|
||||
const { data, error } = await supabase
|
||||
.from('projects')
|
||||
.select('*')
|
||||
.eq('id', 1)
|
||||
.explain({ analyze: true })
|
||||
|
||||
console.log(data)
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
Aggregate (cost=8.18..8.20 rows=1 width=112) (actual time=0.017..0.018 rows=1 loops=1)
|
||||
-> Index Scan using projects_pkey on projects (cost=0.15..8.17 rows=1 width=40) (actual time=0.012..0.012 rows=0 loops=1)
|
||||
Index Cond: (id = 1)
|
||||
Filter: false
|
||||
Rows Removed by Filter: 1
|
||||
Planning Time: 0.092 ms
|
||||
Execution Time: 0.046 ms
|
||||
```
|
||||
|
||||
Here you can see the “Filter” node, which is a simple `false` as defined by the above policy, this proves that the RLS policy is getting applied. Also the actual “Execution Time” is shown, which is a fraction of a millisecond. Note that this is only the query execution time, it doesn’t account for the latency for transferring the data from the database to the frontend.
|
||||
|
||||
### Getting the Query Identifier
|
||||
|
||||
`explain()` is also useful for getting the [pg_stat_statements](https://www.postgresql.org/docs/current/pgstatstatements.html) query identifier, which you can use in the Supabase logs to obtain the generated SQL queries. Here we use the json `format` and the `verbose` option to get it.
|
||||
|
||||
```jsx
|
||||
const { data, error } = await supabase
|
||||
.from('projects')
|
||||
.select('*')
|
||||
.eq('id', 1)
|
||||
.explain({ format: 'json', verbose: true })
|
||||
|
||||
console.log(data[0]['Query Identifier'])
|
||||
// 2811722635570756600
|
||||
```
|
||||
|
||||
For getting more detailed information, you can also use the `settings`, `buffers`, `wal` options with `explain()` .
|
||||
|
||||
## Improved Relationship Detection
|
||||
|
||||
### One-to-one relationships
|
||||
|
||||
To avoid unnecessary JSON arrays in a query result, one-to-one relationships are now automatically detected. For this you can use a:
|
||||
|
||||
```sql
|
||||
-- A unique constraint on a foreign key
|
||||
create table country(
|
||||
id serial primary key
|
||||
, name text
|
||||
);
|
||||
|
||||
create table capital(
|
||||
id serial primary key
|
||||
, name text
|
||||
, country_id int unique
|
||||
, foreign key (country_id) references country(id)
|
||||
);
|
||||
|
||||
-- or a primary key on a foreign key
|
||||
create table country(
|
||||
id serial primary key
|
||||
, name text
|
||||
);
|
||||
|
||||
create table capital(
|
||||
id serial primary key
|
||||
, name text
|
||||
, foreign key (id) references country(id)
|
||||
);
|
||||
```
|
||||
|
||||
Both options should give you a json object when embedding one table with the other.
|
||||
|
||||
```sql
|
||||
const { data, error } = await supabase
|
||||
.from('country')
|
||||
.select('name,capital(name)')
|
||||
.in('id', [1, 2])
|
||||
|
||||
console.log(data)
|
||||
```
|
||||
|
||||
```json noCopy
|
||||
[
|
||||
{ "name": "Afghanistan", "capital": { "name": "Kabul" } },
|
||||
{ "name": "Algeria", "capital": { "name": "Algiers" } }
|
||||
]
|
||||
```
|
||||
|
||||
### Computed relationships
|
||||
|
||||
PostgREST uses foreign keys to detect relationships. This poses a problem on database objects that cannot have foreign keys, like views. Though PostgREST tries to infer relationships based on the views’ source tables foreign keys([docs](https://postgrest.org/en/latest/api.html#embedding-views)), this is not infallible - in particular, it fails when views have a complex definition (e.g. multiple UNIONs). For this you can use “computed relationships”, which are “inlinable” SQL functions similar to computed columns.
|
||||
|
||||
Let’s assume we have a `players` view, a `scores` materialized view and we want to define a one-to-many relationship on them.
|
||||
|
||||
```sql
|
||||
create view players as
|
||||
select id, name from players_a
|
||||
union
|
||||
select id, name from players_b;
|
||||
|
||||
create materialized view scores as
|
||||
select
|
||||
name as lvl_name,
|
||||
compute_score(stats) as total, player_id
|
||||
from level_1;
|
||||
union
|
||||
select
|
||||
name as lvl_name,
|
||||
compute_score(stats) as total,
|
||||
player_id
|
||||
from level_2;
|
||||
```
|
||||
|
||||
For this we can define a couple of computed relationships.
|
||||
|
||||
```sql
|
||||
-- many-to-one relationship on scores -> players
|
||||
create function player(scores)
|
||||
returns setof players rows 1 -- rows 1 defines a "one" end
|
||||
language sql stable
|
||||
as $$
|
||||
select *
|
||||
from players
|
||||
where id = $1.player_id;
|
||||
$$;
|
||||
|
||||
-- one-to-many relationship on players -> scores
|
||||
create function scores(players)
|
||||
returns setof scores -- there's an implicit rows 1000 here, which is assumed to be "many"
|
||||
language sql stable
|
||||
as $$
|
||||
select *
|
||||
from scores
|
||||
where player_id = $1.id;
|
||||
$$;
|
||||
```
|
||||
|
||||
And now we can embed both views from one end to the other. Note that the function names are arbitrary, here we named them similar to the views for convenience.
|
||||
|
||||
```jsx
|
||||
const { data, error } = await supabase
|
||||
.from('scores')
|
||||
.select('lvl_name, player(name)')
|
||||
.eq('lvl_name', "Grand Prix 1")
|
||||
.single()
|
||||
|
||||
console.log(data)
|
||||
|
||||
{
|
||||
"lvl_name": "Grand Prix 1",
|
||||
"player": { "name": "Ben Richards"}
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('players')
|
||||
.select('name,scores(lvl_name, total)')
|
||||
.eq('id', 1)
|
||||
.single()
|
||||
|
||||
console.log(data)
|
||||
|
||||
{
|
||||
"name":"Ben Richards",
|
||||
"scores":[
|
||||
{"lvl_name": "Grand Prix 1", "total": 48761.24},
|
||||
{"lvl_name": "Grand Prix 2", "total": -40.25}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Computed relationships follow the rules of [Inlining of SQL Functions](https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions), which basically allows them to be injected into PostgREST generated queries, making them efficient to use. You can also use computed relationships to override detected relationships.
|
||||
|
||||
### Breaking change on many-to-many relationships
|
||||
|
||||
Detecting join tables for many-to-many relationships has been working for many releases. However on complex schemas join tables can be incorrectly detected, causing errors when used in resource embedding. For this the following BREAKING CHANGE had to be made:
|
||||
|
||||
```sql
|
||||
-- for "books_authors" to be detected as a join table,
|
||||
-- the primary key must include the foreign key columns
|
||||
-- of the many-to-many ends
|
||||
|
||||
create table books(
|
||||
id int primary key
|
||||
, name text
|
||||
);
|
||||
|
||||
create table books_authors(
|
||||
book_id int references books(id)
|
||||
, author_id int references authors(id)
|
||||
, primary key(book_id, author_id) -- this is now necessary
|
||||
);
|
||||
|
||||
create table authors(
|
||||
id int primary key
|
||||
, name text
|
||||
);
|
||||
```
|
||||
|
||||
If changing the PK is not feasible for a particular case, the alternative would be using computed relationships to define the many-to-many.
|
||||
|
||||
One-to-many and many-to-one relationships keep working as always, no change in their detection.
|
||||
|
||||
## Closing up
|
||||
|
||||
Computed relationships are the first step towards PostgREST extensibility, customizing the aggregate used for the response and custom operators are planned for next releases.
|
||||
|
||||
We’ll release PostgREST 10 on the Supabase platform over the next month.
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
title: 'Supabase Vault'
|
||||
description: "Today we're announcing Vault, a Postgres extension for managing secrets and encryption inside your database."
|
||||
author: michel
|
||||
image: lw5-vault/lw5-vault.jpg
|
||||
thumb: lw5-vault/lw5-vault.jpg
|
||||
tags:
|
||||
- launch-week
|
||||
date: '2022-08-19'
|
||||
toc_depth: 2
|
||||
---
|
||||
|
||||
Today we're announcing [Supabase Vault](https://github.com/supabase/vault), a Postgres extension for managing secrets and encryption inside your database.
|
||||
Vault is a thin usability-layer on top of [pgsodium](https://github.com/michelp/pgsodium).
|
||||
|
||||
Vault is not available on the Supabase platform yet. We're finalizing usability and security testing.
|
||||
This release is intended to gather user-feedback from our community and customers.
|
||||
|
||||
Soon, we'll release a blog post that describes more about the technology behind Vault - [libsodium](https://doc.libsodium.org/) and
|
||||
[pgsodium](https://doc.libsodium.org/). For now, we will go through a quick example of storing a secret, like a service access token, into the Vault.
|
||||
|
||||
## Background
|
||||
|
||||
Until now, the industry-standard for PostgreSQL encryption is a built-in extension called [`pgcrypto`](https://www.postgresql.org/docs/current/pgcrypto.html).
|
||||
Like most cloud providers, Supabase offers `pgcrypto` for developers to use in their applications. `pgcrypto` has been around for a long time,
|
||||
and while it supports some basic encryption and decryption abilities, it lacks features like public key signing, key derivation APIs, streaming encryption,
|
||||
and other modern features required by security-first applications.
|
||||
|
||||
### Problems with raw keys
|
||||
|
||||
Databases often store sensitive information, and they need tools that guarantee this data is stored and backed-up in an encrypted form.
|
||||
A fundamental issue with `pgcrypto` is that it lacks the ability to derive keys from outside of SQL. Instead you must have the raw encryption key for the algorithm you wish to use:
|
||||
|
||||
```sql
|
||||
create extension pgcrypto;
|
||||
|
||||
create table users (
|
||||
id serial primary key,
|
||||
email varchar not null unique
|
||||
);
|
||||
|
||||
insert into users
|
||||
(email)
|
||||
values
|
||||
(pgp_sym_encrypt('alice@supabase.io', 's3kr3t_k3y')),
|
||||
(pgp_sym_encrypt('bob@supabase.io', 's3kr3t_key'));
|
||||
```
|
||||
|
||||
pgcrypto works with _raw_ keys. In order to encrypt the data with pgcrypto you must pass the key directly to the encryption function.
|
||||
Leaking those raw keys is all too easy - logs, files, clients, tables, replication streams - you name it.
|
||||
Wouldn't it be great if you could encrypt data, but instead of specifying the raw key you reference it indirectly, like with a key ID?
|
||||
|
||||
## Supabase Vault
|
||||
|
||||
Supabase Vault allows you to store secrets without leaking any sensitive information.
|
||||
|
||||
The Vault is a good place to put things like API keys, access tokens, and other secrets from external services that you need to access within your database.
|
||||
The core of the Supabase Vault is a table with some metadata and an encrypted text column where you can put your secrets and any metadata related to them.
|
||||
|
||||
We take the pain out of key management by pre-generating a unique, per-database key that is used by default - a “root” key - which is stored outside of the SQL language,
|
||||
accessibly only internally in the Postgres server by the libsodium library. This root key is managed by the [pgsodium](https://github.com/michelp/pgsodium) Postgres extension
|
||||
when the server boots using [Server Key Management.](https://github.com/michelp/pgsodium#server-key-management)
|
||||
|
||||
pgsodium provides an Encryption and Key Derivation API based on the [libsodium library](https://libsodium.gitbook.io/doc/) and can get it's root key from a
|
||||
variety of sources depending on how you configure it. Supabase generates and preserves your project's root key behind the scenes, so you don't have to worry about it.
|
||||
If you install pgsodium locally the default is to generate a random root key from the `/dev/urandom` device which is then saved in a file in your Postgres data directory.
|
||||
|
||||
Installing the `vault` extension is the same as any other Postgres extension:
|
||||
|
||||
```sql
|
||||
create extension vault with schema vault;
|
||||
```
|
||||
|
||||
Once enabled, you can insert secrets into the `vault.secrets` table:
|
||||
|
||||
```sql
|
||||
insert into vault.secrets
|
||||
(secret, associated)
|
||||
values
|
||||
('s3kr3t_k3y', 'This is the secret API service key.');
|
||||
```
|
||||
|
||||
Now when you look in the `vault.secrets` table, the secret is encrypted:
|
||||
|
||||
```sql
|
||||
select * from vault.secrets;
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
-[ RECORD 1 ]--------------------------------------------------------
|
||||
id | f6a2fe0a-3471-4eea-a581-75c4d2be396b
|
||||
secret | /eT9bb96POTJ7L2gYrluTZ3r3pG5IMwPSQo6pQP0xdZTarpRrpWPXTWQ
|
||||
key_id | caabfc28-2ab3-48f5-8978-1b3d4b659911
|
||||
associated | This is the secret API service key.
|
||||
nonce | \x77c7381c523630ba72f1f137626a9f9a
|
||||
created_at | 2022-08-18 19:33:15.312651+00
|
||||
```
|
||||
|
||||
Notice how the row has a `key_id` column. This is the _ID_ of the internally derived key that is used to encrypt the secret, not the key itself.
|
||||
The actual raw key is not available to you in SQL, it is managed entirely outside of the SQL language in the Postgres server.
|
||||
|
||||
At Supabase, we manage this key for your project automatically and generate a unique default Key ID for you in the `secrets` table.
|
||||
For self-hosting, pgsodium [supports a variety of ways](https://github.com/michelp/pgsodium#server-key-management) to place the root key into Postgres.
|
||||
|
||||
To see the decrypted data, there is a special view created called `vault.decrypted_secrets`:
|
||||
|
||||
```sql
|
||||
select * from vault.decrypted_secrets;
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
-[ RECORD 1 ]----+---------------------------------------------------------
|
||||
id | f6a2fe0a-3471-4eea-a581-75c4d2be396b
|
||||
secret | /eT9bb96POTJ7L2gYrluTZ3r3pG5IMwPSQo6pQP0xdZTarpRrpWPXTWQ
|
||||
decrypted_secret | s3kr3t_k3y
|
||||
key_id | caabfc28-2ab3-48f5-8978-1b3d4b659911
|
||||
associated | This is the secret API service key.
|
||||
nonce | \x77c7381c523630ba72f1f137626a9f9a
|
||||
created_at | 2022-08-18 19:33:15.312651+00
|
||||
```
|
||||
|
||||
Now you can see a new `decrypted_secret` column that contains the decrypted secret we originally inserted into the table.
|
||||
This `vault.decrypted_secrets` view automatically decrypts rows in the `vault.secrets` table “on-the-fly” as you query them, but the secret is stored on disk in _encrypted_ form.
|
||||
If you take a backup, or pause your project, that data remains encrypted. We will keep your hidden root key safe in our backend systems for when you need to restore or un-pause your projects.
|
||||
|
||||
If you wish to use your own Key ID for different secrets, insted of the default Key ID we've generated, you can create one using the `pgsodium.create_key()` function:
|
||||
|
||||
```sql
|
||||
select * from pgsodium.create_key('This is a comment for the new key');
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
-[ RECORD 1 ]-------------------------------------
|
||||
id | f9f176eb-7069-4743-9403-582c04354ffc
|
||||
status | valid
|
||||
created | 2022-08-18 22:31:50.331792
|
||||
expires |
|
||||
key_type | aead-det
|
||||
key_id | 2
|
||||
key_context | \x7067736f6469756d
|
||||
comment | This is the comment for the new key
|
||||
user_data |
|
||||
```
|
||||
|
||||
Now you can encrypt table secrets with this new key by inserting its ID explicitly:
|
||||
|
||||
```sql
|
||||
insert into vault.secrets
|
||||
(secret, associated, key_id)
|
||||
values (
|
||||
'apikey_XaYrurzcquqhEdBjzfTzfwAZqpd',
|
||||
'This is some different associated data.',
|
||||
'f9f176eb-7069-4743-9403-582c04354ffc'
|
||||
)
|
||||
returning *;
|
||||
```
|
||||
|
||||
```text hideCopy
|
||||
-[ RECORD 1 ]------------------------------------------------------------
|
||||
id | 9c58a0f3-aa40-4789-b683-6db48b241f9e
|
||||
secret | YWxuTnWdF55MuRrZ7xneBvaz2uH59U1dJV/7CCZjSn5B5jELOoy/csq8x/s=
|
||||
key_id | f9f176eb-7069-4743-9403-582c04354ffc
|
||||
associated | This is some different associated data.
|
||||
nonce | \xd39808b07c9ae52c8f02c33a7f87595c
|
||||
created_at | 2022-08-18 22:34:07.219941+00
|
||||
```
|
||||
|
||||
The type of encryption used by the Vault is called [Authenticated Encryption with Associated Data](https://en.wikipedia.org/wiki/Authenticated_encryption).
|
||||
The data you insert into the `associated` column, which is up to you, is combined with the encrypted text when libsodium creates the authentication signature for the secret.
|
||||
This means that when you read the secret, you know that the associated data is also authentic. The associated data could be an account ID or some
|
||||
information that ties your system to the secret. And as always, you can refer to rows in the secrets table by their primary key UUID.
|
||||
|
||||
If you only want to store secrets that you know are encrypted on disk and in backups, then all you need to know is shown above. Just insert secrets into the table,
|
||||
optionally creating new keys, and select them from the view when you want to use them.
|
||||
|
||||
## Going Beyond the Vault
|
||||
|
||||
The Vault is good for a reasonable amount of secure data, like API keys, access tokens, or environment variables.
|
||||
But if you have a lot more sensitive information, like personally Identifiable Information (PII),
|
||||
you may want to break them out into side-tables using pgsodium's
|
||||
[Transparent Column Encryption](https://github.com/michelp/pgsodium#transparent-column-encryption) which we will describe soon in a follow-up blog post. Stay tuned!
|
||||
@@ -1,251 +0,0 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
// Auth,
|
||||
Space,
|
||||
Tabs,
|
||||
IconCode,
|
||||
IconSearch,
|
||||
} from '@supabase/ui'
|
||||
import CodeBlock from '../CodeBlock/CodeBlock'
|
||||
// Import Swiper React components
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useTheme } from '../Providers'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYxNTIxNDE1MywiZXhwIjoxOTMwNzkwMTUzfQ.OQEbAaTfgDdLCCht251P2JRD3QDnui6nsU8N-tZA_Mc'
|
||||
)
|
||||
|
||||
function AuthComponentExample() {
|
||||
const { isDarkMode } = useTheme()
|
||||
const { basePath } = useRouter()
|
||||
|
||||
// // store API swiper instance
|
||||
// const [imageSwiper, setImageSwiper] = useState(undefined)
|
||||
// const [imageSwiperActiveIndex, setImageSwiperActiveIndex] = useState(0)
|
||||
|
||||
// function handleNavChange(e: number) {
|
||||
// console.log(e)
|
||||
// setImageSwiperActiveIndex(e)
|
||||
// // @ts-ignore
|
||||
// imageSwiper.slideTo(e)
|
||||
// }
|
||||
|
||||
// const AuthContainer = (props: any) => {
|
||||
// const { user } = Auth.useUser()
|
||||
// if (user) {
|
||||
// return (
|
||||
// <>
|
||||
// <p>Signed in: {user.email}</p>
|
||||
// <Button block onClick={() => props.supabaseClient.auth.signOut()}>
|
||||
// Sign out
|
||||
// </Button>
|
||||
// </>
|
||||
// )
|
||||
// }
|
||||
// return props.children
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="sbui-tabs--alt">
|
||||
{/* <Tabs
|
||||
activeId={imageSwiperActiveIndex.toString()}
|
||||
onChange={(id: string) => handleNavChange(Number(id))}
|
||||
>
|
||||
<Tabs.Panel label="Preview" id="0" icon={<IconSearch />}>
|
||||
<span></span>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel label="Code" icon={<IconCode />} id="1">
|
||||
<span></span>
|
||||
</Tabs.Panel>
|
||||
</Tabs> */}
|
||||
<div
|
||||
className={`auth-container relative border bg-white py-2 pb-16 dark:border-gray-600 dark:bg-gray-800`}
|
||||
>
|
||||
<Swiper
|
||||
// @ts-ignore
|
||||
onSwiper={setImageSwiper}
|
||||
style={{ zIndex: 0 }}
|
||||
initialSlide={0}
|
||||
spaceBetween={0}
|
||||
slidesPerView={1}
|
||||
speed={300}
|
||||
autoHeight={true}
|
||||
allowTouchMove={false}
|
||||
>
|
||||
<SwiperSlide key={1}>
|
||||
<div className="pt-8" style={{ maxWidth: '420px', margin: '0 auto' }}>
|
||||
<Card>
|
||||
<Space size={4} direction="vertical">
|
||||
<div>
|
||||
<Space size={3} direction="vertical">
|
||||
<img
|
||||
src={
|
||||
isDarkMode
|
||||
? `${basePath}/brand-assets/supabase-logo-wordmark--dark.svg`
|
||||
: `${basePath}/brand-assets/supabase-logo-wordmark--light.svg`
|
||||
}
|
||||
width="96"
|
||||
alt="Logo"
|
||||
/>
|
||||
<h3>{'Acme Company'}</h3>
|
||||
</Space>
|
||||
<Badge dot>Demo</Badge>
|
||||
</div>
|
||||
<p>Sign in with</p>
|
||||
<div className="flex justify-evenly">
|
||||
<Link href="https://supabase.com/docs/guides/auth/auth-facebook">
|
||||
<Button type="default" size="large">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="https://supabase.com/docs/guides/auth/auth-google">
|
||||
<Button type="default" size="large">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 488 512"
|
||||
width="22"
|
||||
height="22"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="https://supabase.com/docs/guides/auth/auth-github">
|
||||
<Button type="default" size="large">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 249"
|
||||
width="22"
|
||||
height="22"
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<path d="M127.505 0C57.095 0 0 57.085 0 127.505c0 56.336 36.534 104.13 87.196 120.99 6.372 1.18 8.712-2.766 8.712-6.134 0-3.04-.119-13.085-.173-23.739-35.473 7.713-42.958-15.044-42.958-15.044-5.8-14.738-14.157-18.656-14.157-18.656-11.568-7.914.872-7.752.872-7.752 12.804.9 19.546 13.14 19.546 13.14 11.372 19.493 29.828 13.857 37.104 10.6 1.144-8.242 4.449-13.866 8.095-17.05-28.32-3.225-58.092-14.158-58.092-63.014 0-13.92 4.981-25.295 13.138-34.224-1.324-3.212-5.688-16.18 1.235-33.743 0 0 10.707-3.427 35.073 13.07 10.17-2.826 21.078-4.242 31.914-4.29 10.836.048 21.752 1.464 31.942 4.29 24.337-16.497 35.029-13.07 35.029-13.07 6.94 17.563 2.574 30.531 1.25 33.743 8.175 8.929 13.122 20.303 13.122 34.224 0 48.972-29.828 59.756-58.22 62.912 4.573 3.957 8.648 11.717 8.648 23.612 0 17.06-.148 30.791-.148 34.991 0 3.393 2.295 7.369 8.759 6.117 50.634-16.879 87.122-64.656 87.122-120.973C255.009 57.085 197.922 0 127.505 0" />
|
||||
<path d="M47.755 181.634c-.28.633-1.278.823-2.185.389-.925-.416-1.445-1.28-1.145-1.916.275-.652 1.273-.834 2.196-.396.927.415 1.455 1.287 1.134 1.923M54.027 187.23c-.608.564-1.797.302-2.604-.589-.834-.889-.99-2.077-.373-2.65.627-.563 1.78-.3 2.616.59.834.899.996 2.08.36 2.65M58.33 194.39c-.782.543-2.06.034-2.849-1.1-.781-1.133-.781-2.493.017-3.038.792-.545 2.05-.055 2.85 1.07.78 1.153.78 2.513-.019 3.069M65.606 202.683c-.699.77-2.187.564-3.277-.488-1.114-1.028-1.425-2.487-.724-3.258.707-.772 2.204-.555 3.302.488 1.107 1.026 1.445 2.496.7 3.258M75.01 205.483c-.307.998-1.741 1.452-3.185 1.028-1.442-.437-2.386-1.607-2.095-2.616.3-1.005 1.74-1.478 3.195-1.024 1.44.435 2.386 1.596 2.086 2.612M85.714 206.67c.036 1.052-1.189 1.924-2.705 1.943-1.525.033-2.758-.818-2.774-1.852 0-1.062 1.197-1.926 2.721-1.951 1.516-.03 2.758.815 2.758 1.86M96.228 206.267c.182 1.026-.872 2.08-2.377 2.36-1.48.27-2.85-.363-3.039-1.38-.184-1.052.89-2.105 2.367-2.378 1.508-.262 2.857.355 3.049 1.398" />
|
||||
</g>
|
||||
</svg>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="https://supabase.com/docs/guides/auth/auth-bitbucket">
|
||||
<Button type="default" size="large">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
width="22"
|
||||
height="22"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22.2 32A16 16 0 0 0 6 47.8a26.35 26.35 0 0 0 .2 2.8l67.9 412.1a21.77 21.77 0 0 0 21.3 18.2h325.7a16 16 0 0 0 16-13.4L505 50.7a16 16 0 0 0-13.2-18.3 24.58 24.58 0 0 0-2.8-.2L22.2 32zm285.9 297.8h-104l-28.1-147h157.3l-25.2 147z"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="https://supabase.com/docs/guides/auth/auth-gitlab">
|
||||
<Button type="default" size="large">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
width="22"
|
||||
height="22"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M105.2 24.9c-3.1-8.9-15.7-8.9-18.9 0L29.8 199.7h132c-.1 0-56.6-174.8-56.6-174.8zM.9 287.7c-2.6 8 .3 16.9 7.1 22l247.9 184-226.2-294zm160.8-88l94.3 294 94.3-294zm349.4 88l-28.8-88-226.3 294 247.9-184c6.9-5.1 9.7-14 7.2-22zM425.7 24.9c-3.1-8.9-15.7-8.9-18.9 0l-56.6 174.8h132z"
|
||||
></path>
|
||||
</svg>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex w-full flex-row items-center justify-center">
|
||||
<div className="h-[1px] w-full bg-gray-500" />
|
||||
<p className="w-full text-center text-gray-500">or continue with</p>
|
||||
<div className="h-[1px] w-full bg-gray-500" />
|
||||
</div>
|
||||
{/* <Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<AuthContainer supabaseClient={supabase}>
|
||||
<Auth supabaseClient={supabase} />
|
||||
</AuthContainer>
|
||||
</Auth.UserContextProvider> */}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
|
||||
<SwiperSlide key={2}>
|
||||
<div className="p-8">
|
||||
<CodeBlock
|
||||
children={`import React, { useState } from 'react'
|
||||
import { Auth, Button } from '@supabase/ui'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
export default function app() {
|
||||
const supabase = createClient(
|
||||
"https://YOUR-PROJECT-ID.supabase.co",
|
||||
"YOUR-PUBLIC-ANON-KEY"
|
||||
);
|
||||
|
||||
function Container(props: any) {
|
||||
const { user } = Auth.useUser();
|
||||
if (user) {
|
||||
return (
|
||||
<div>
|
||||
<p>Signed in: {user.email}</p>
|
||||
<Button block onClick={() => props.supabaseClient.auth.signOut()}>
|
||||
Sign out
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return props.children;
|
||||
};
|
||||
|
||||
return (
|
||||
<Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<Container supabaseClient={supabase}>
|
||||
<Auth supabaseClient={supabase} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
);
|
||||
}
|
||||
`}
|
||||
lang="js"
|
||||
/>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthComponentExample
|
||||
@@ -1,239 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { createClient, Provider } from '@supabase/supabase-js'
|
||||
|
||||
import DefaultLayout from '~/components/Layouts/Default'
|
||||
import CodeBlock from '~/components/CodeBlock/CodeBlock'
|
||||
import {
|
||||
Button,
|
||||
// Auth,
|
||||
Card,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Radio,
|
||||
Select,
|
||||
Space,
|
||||
Tabs,
|
||||
Input,
|
||||
Toggle,
|
||||
IconCode,
|
||||
IconZoomIn,
|
||||
IconCopy,
|
||||
IconColumns,
|
||||
} from '@supabase/ui'
|
||||
|
||||
import AuthStyles from './Auth.module.css'
|
||||
|
||||
function AuthPage() {
|
||||
const supabase = createClient(
|
||||
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYxNTIxNDE1MywiZXhwIjoxOTMwNzkwMTUzfQ.OQEbAaTfgDdLCCht251P2JRD3QDnui6nsU8N-tZA_Mc'
|
||||
)
|
||||
|
||||
type SizeProps = 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
|
||||
type LayoutProps = 'horizontal' | 'vertical'
|
||||
|
||||
const [companyName, setCompanyName] = useState('Acme Company')
|
||||
const [widgetSize, setWidgetSize] = useState<SizeProps>('tiny')
|
||||
const [socialLogins, setSocialLogins] = useState(true)
|
||||
const [socialLoginLayout, setSocialLoginLayout] = useState<LayoutProps>('horizontal')
|
||||
const [socialColors, setSocialColors] = useState(false)
|
||||
|
||||
const socials: Provider[] = ['facebook', 'google', 'bitbucket', 'github', 'gitlab']
|
||||
|
||||
const formSize = 'small'
|
||||
const formLayout = 'vertical'
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="container relative mx-auto px-8 py-32 sm:px-16 xl:px-20">
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-8">
|
||||
<h2 className="mb-4">ReactJS Auth Widget</h2>
|
||||
<p>
|
||||
An API built from the groud up just for Storage.With powerful library clients coming
|
||||
soon that allow for asset optimasation and image transformation
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-8">
|
||||
<div
|
||||
className={`relative border-t border-l border-b bg-white py-2 pb-16 dark:border-gray-600 dark:bg-gray-800 ${AuthStyles['auth-container']}`}
|
||||
>
|
||||
<div className="left-0 top-2 h-full w-full">
|
||||
<Tabs
|
||||
size="medium"
|
||||
defaultActiveId="panel-1"
|
||||
type="underlined"
|
||||
tabBarStyle={{ padding: '0 16px' }}
|
||||
addOnAfter={[
|
||||
<Space>
|
||||
<Button type="outline" icon={<IconCopy />}>
|
||||
Copy code
|
||||
</Button>
|
||||
<Button type="outline" icon={<IconColumns />}>
|
||||
Customise
|
||||
</Button>
|
||||
</Space>,
|
||||
]}
|
||||
>
|
||||
<Tabs.Panel label="Preview" id="panel-1" icon={<IconZoomIn />}>
|
||||
<div style={{ maxWidth: '420px', margin: '0 auto' }}>
|
||||
<Card>
|
||||
<Space size={8} direction="vertical">
|
||||
<div>
|
||||
<Space size={3} direction="vertical">
|
||||
<img
|
||||
src="https://app.supabase.com/img/supabase-dark.svg"
|
||||
width="96"
|
||||
alt="supabase logo"
|
||||
/>
|
||||
<h3>{companyName}</h3>
|
||||
</Space>
|
||||
</div>
|
||||
{/* <Auth
|
||||
providers={socialLogins ? socials : []}
|
||||
socialButtonSize={widgetSize}
|
||||
socialLayout={socialLoginLayout}
|
||||
supabaseClient={supabase}
|
||||
socialColors={socialColors}
|
||||
/> */}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel label="Code" icon={<IconCode />} id="panel-2">
|
||||
<div className="h-full">
|
||||
<CodeBlock
|
||||
hideCopy
|
||||
children={`// Auth example
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { Auth } from './'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
// @ts-ignore
|
||||
import { Button, Space } from '../../index'
|
||||
|
||||
export default function app() {
|
||||
|
||||
const supabase = createClient(
|
||||
'https://YOUR-PROJECT-ID.supabase.co',
|
||||
'YOUR-PUBLIC-ANON-KEY'
|
||||
)
|
||||
|
||||
return (
|
||||
<Auth.UserContextProvider {...args}>
|
||||
<Container {...args}>
|
||||
<Auth {...args} />
|
||||
</Container>
|
||||
</Auth.UserContextProvider>
|
||||
)
|
||||
}
|
||||
`}
|
||||
lang="js"
|
||||
/>
|
||||
</div>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-span-4">
|
||||
<div className="h-full rounded rounded-l-none border bg-white dark:border-gray-600 dark:bg-gray-800">
|
||||
<div className={`p-8`}>
|
||||
<Space size={12} direction="vertical">
|
||||
<div>
|
||||
<h3>Customise your login form</h3>
|
||||
<p>Our ReactJS Auth form will help you get going even quicker </p>
|
||||
</div>
|
||||
<Divider light />
|
||||
<Input
|
||||
size={formSize}
|
||||
layout={formLayout}
|
||||
label="Name of app"
|
||||
value={companyName}
|
||||
onChange={(e) => setCompanyName(e.target.value)}
|
||||
/>
|
||||
{/* @ts-ignore */}
|
||||
<Space size={8} direction="vertical">
|
||||
<Card>
|
||||
<Space size={8} direction="vertical">
|
||||
<Checkbox
|
||||
size={formSize}
|
||||
label="Show social logins"
|
||||
description=" "
|
||||
checked={socialLogins}
|
||||
onChange={() => setSocialLogins(!socialLogins)}
|
||||
/>
|
||||
{socialLogins && (
|
||||
<>
|
||||
<Divider light />
|
||||
{/* @ts-ignore */}
|
||||
<Radio.Group
|
||||
size={formSize}
|
||||
type="cards"
|
||||
label="Social button layout"
|
||||
layout={formLayout}
|
||||
name="layout-group"
|
||||
value={socialLoginLayout}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
// @ts-ignore
|
||||
setSocialLoginLayout(e.target.value)
|
||||
}
|
||||
>
|
||||
<Radio
|
||||
name="layout-group"
|
||||
key={'horizontal'}
|
||||
label={'horizontal'}
|
||||
value={'horizontal'}
|
||||
/>
|
||||
<Radio
|
||||
name="layout-group"
|
||||
key={'vertical'}
|
||||
label={'vertical'}
|
||||
value={'vertical'}
|
||||
/>
|
||||
</Radio.Group>
|
||||
<Toggle
|
||||
size={formSize}
|
||||
layout="vertical"
|
||||
align="right"
|
||||
labelOptional="Use brand colors on buttons"
|
||||
label="Social colors"
|
||||
// descriptionText="Show the brand colors of the social logins in the buttons"
|
||||
checked={socialColors}
|
||||
onChange={() => setSocialColors(!socialColors)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</Space>
|
||||
<Radio.Group
|
||||
size={formSize}
|
||||
type="cards"
|
||||
label="Form size"
|
||||
labelOptional="This is an optional label"
|
||||
descriptionText="This controls the button sizes and form input sizes"
|
||||
layout={formLayout}
|
||||
name="size-group"
|
||||
value={widgetSize}
|
||||
/* @ts-ignore */
|
||||
onChange={(e) => setWidgetSize(e.target.value)}
|
||||
>
|
||||
<Radio name="size-group" key={1} label={'tiny'} value={'tiny'} />
|
||||
<Radio name="size-group" key={2} label={'small'} value={'small'} />
|
||||
<Radio name="size-group" key={3} label={'medium'} value={'medium'} />
|
||||
<Radio name="size-group" key={3} label={'large'} value={'large'} />
|
||||
<Radio name="size-group" key={3} label={'xlarge'} value={'xlarge'} />
|
||||
</Radio.Group>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthPage
|
||||
@@ -0,0 +1,290 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Button } from '@supabase/ui'
|
||||
import { useState } from 'react'
|
||||
// Import Swiper React components
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { ColorSwatchIcon, MenuIcon } from '@heroicons/react/outline'
|
||||
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
|
||||
import { useTheme } from '../Providers'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYxNTIxNDE1MywiZXhwIjoxOTMwNzkwMTUzfQ.OQEbAaTfgDdLCCht251P2JRD3QDnui6nsU8N-tZA_Mc'
|
||||
)
|
||||
|
||||
function AuthWidgetSection() {
|
||||
const { isDarkMode } = useTheme()
|
||||
const { basePath } = useRouter()
|
||||
const [radius, setRadius] = useState('4px')
|
||||
const [brandColor, setBrandColor] = useState({
|
||||
brand: 'var(--colors-brand9)',
|
||||
brandAccent: 'var(--colors-brand11)',
|
||||
brandAccent2: 'var(--colors-brand3)',
|
||||
})
|
||||
const [layout, setLayout] = useState('horizontal')
|
||||
|
||||
// // store API swiper instance
|
||||
const [imageSwiper, setImageSwiper] = useState(undefined)
|
||||
const [imageSwiperActiveIndex, setImageSwiperActiveIndex] = useState(0)
|
||||
|
||||
function handleNavChange(e: number) {
|
||||
console.log(e)
|
||||
setImageSwiperActiveIndex(e)
|
||||
// @ts-ignore
|
||||
imageSwiper.slideTo(e)
|
||||
}
|
||||
|
||||
const AuthContainer = (props: any) => {
|
||||
const { user } = Auth.useUser()
|
||||
if (user) {
|
||||
return (
|
||||
<>
|
||||
<p>Signed in: {user.email}</p>
|
||||
<Button block onClick={() => props.supabaseClient.auth.signOut()}>
|
||||
Sign out
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return props.children
|
||||
}
|
||||
|
||||
// rounded-xl rounded-3xl rounded-full // for purging
|
||||
|
||||
return (
|
||||
<div className="sbui-tabs--alt overflow-hidden">
|
||||
<div className={`dark:bg-scale-200 bg-scale-100 relative border py-2 pb-16`}>
|
||||
<div className="sm:py-18 gap container relative mx-auto grid grid-cols-12 px-6 py-16 md:gap-16 md:py-24 lg:gap-16 lg:px-16 lg:py-24 xl:px-20">
|
||||
<div className="relative z-10 col-span-12 mb-16 md:col-span-7 md:mb-0 lg:col-span-6">
|
||||
<div className="relative lg:mx-auto lg:max-w-md">
|
||||
<div className="glow-area transition-all"></div>
|
||||
|
||||
<div className="border-scale-400 dark:bg-scale-300 pointer-events-none relative rounded-xl border bg-white px-8 py-12 drop-shadow-sm">
|
||||
<div className="mb-6 flex flex-col gap-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className="w-10 rounded-full p-2"
|
||||
style={{
|
||||
background: brandColor.brandAccent2,
|
||||
color: brandColor.brand,
|
||||
}}
|
||||
>
|
||||
<ColorSwatchIcon strokeWidth={1.5} />
|
||||
</div>
|
||||
<h1 className="text-scale-1200 text-2xl">Acne Company Ltd</h1>
|
||||
</div>
|
||||
<p className="text-scale-1100 text-auth-widget-test">
|
||||
Sign in today for Supa stuff
|
||||
</p>
|
||||
</div>
|
||||
<Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<AuthContainer supabaseClient={supabase}>
|
||||
<Auth
|
||||
// @ts-ignore
|
||||
socialLayout={layout}
|
||||
theme={isDarkMode ? 'dark' : 'default'}
|
||||
providers={['google', 'facebook', 'twitter']}
|
||||
supabaseClient={supabase}
|
||||
localization={{
|
||||
lang: 'en',
|
||||
}}
|
||||
appearance={{
|
||||
theme: ThemeSupa,
|
||||
variables: {
|
||||
default: {
|
||||
colors: {
|
||||
brand: brandColor.brand,
|
||||
brandAccent: brandColor.brandAccent,
|
||||
},
|
||||
radii: {
|
||||
borderRadiusButton: radius,
|
||||
buttonBorderRadius: radius,
|
||||
inputBorderRadius: radius,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</AuthContainer>
|
||||
</Auth.UserContextProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-5 lg:col-span-6">
|
||||
<div className="prose !max-w-md">
|
||||
<h3 className="text-2xl">Auth UI</h3>
|
||||
<p className="!mb-0">Pre-built auth widgets to get started in minutes.</p>
|
||||
<p className="text-scale-900 mt-0">
|
||||
Customizable authentication UI component with custom themes and extensible styles to
|
||||
match your brand and aesthetic
|
||||
</p>
|
||||
<div className="mb-4 flex items-center space-x-2">
|
||||
<img className="m-0 w-8" src={`${basePath}/images/product/auth/react-icon.svg`} />
|
||||
<small>React only. Other frameworks coming soon.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-8 py-8 lg:grid-cols-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-scale-1200 text-base">Brand color</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() =>
|
||||
setBrandColor({
|
||||
brand: 'var(--colors-brand9)',
|
||||
brandAccent: 'var(--colors-brand11)',
|
||||
brandAccent2: 'var(--colors-brand3)',
|
||||
})
|
||||
}
|
||||
className={[
|
||||
'bg-brand-300 border-brand-900 h-10 w-10 rounded-full border-2 transition hover:scale-105',
|
||||
brandColor.brand === 'var(--colors-brand9)'
|
||||
? ' !bg-brand-900 ring-scale-400 border-scale-800 ring-2 drop-shadow-lg dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
></button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setBrandColor({
|
||||
brand: 'var(--colors-orange9)',
|
||||
brandAccent: 'var(--colors-orange11)',
|
||||
brandAccent2: 'var(--colors-orange3)',
|
||||
})
|
||||
}
|
||||
className={[
|
||||
'h-10 w-10 rounded-full border-2 border-orange-900 bg-orange-300 transition hover:scale-105 ',
|
||||
brandColor.brand === 'var(--colors-orange9)'
|
||||
? ' ring-scale-400 border-scale-800 !bg-orange-900 ring-2 drop-shadow-lg dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
></button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setBrandColor({
|
||||
brand: 'var(--colors-crimson9)',
|
||||
brandAccent: 'var(--colors-crimson11)',
|
||||
brandAccent2: 'var(--colors-crimson3)',
|
||||
})
|
||||
}
|
||||
className={[
|
||||
'border-crimson-900 bg-crimson-300 h-10 w-10 rounded-full border-2 transition hover:scale-105 ',
|
||||
brandColor.brand === 'var(--colors-crimson9)'
|
||||
? ' ring-scale-400 border-scale-800 !bg-crimson-900 ring-2 drop-shadow-lg dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
></button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setBrandColor({
|
||||
brand: 'var(--colors-indigo9)',
|
||||
brandAccent: 'var(--colors-indigo11)',
|
||||
brandAccent2: 'var(--colors-indigo3)',
|
||||
})
|
||||
}
|
||||
className={[
|
||||
'h-10 w-10 rounded-full border-2 border-indigo-900 bg-indigo-300 transition hover:scale-105 ',
|
||||
brandColor.brand === 'var(--colors-indigo9)'
|
||||
? ' ring-scale-400 border-scale-800 !bg-indigo-900 ring-2 drop-shadow-lg dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-scale-1200 text-base">Rounded corners</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setRadius('4px')}
|
||||
className={[
|
||||
'bg-scale-100 dark:bg-scale-400 border-scale-500 ring-scale-400 border-scale-800 flex h-10 w-10 items-center justify-center rounded-full border hover:scale-105',
|
||||
radius === '4px'
|
||||
? 'ring-scale-400 border-scale-800 border-2 ring-2 dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
<img
|
||||
src="/images/auth-ui/small--light.svg"
|
||||
className="hidden w-4 text-red-900 dark:block"
|
||||
/>
|
||||
<img
|
||||
src="/images/auth-ui/small--dark.svg"
|
||||
className="block w-4 text-red-900 dark:hidden"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setRadius('10px')}
|
||||
className={[
|
||||
'bg-scale-100 dark:bg-scale-400 border-scale-500 flex h-10 w-10 items-center justify-center rounded-full border transition hover:scale-105',
|
||||
radius === '10px'
|
||||
? 'ring-scale-400 border-scale-800 border-2 ring-2 dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
<img
|
||||
src="/images/auth-ui/medium--light.svg"
|
||||
className="hidden w-4 text-red-900 dark:block"
|
||||
/>
|
||||
<img
|
||||
src="/images/auth-ui/medium--dark.svg"
|
||||
className="block w-4 text-red-900 dark:hidden"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setRadius('32px')}
|
||||
className={[
|
||||
'bg-scale-100 dark:bg-scale-400 border-scale-500 flex h-10 w-10 items-center justify-center rounded-full border transition hover:scale-105',
|
||||
radius === '32px'
|
||||
? 'ring-scale-400 border-scale-800 border-2 ring-2 dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
<img
|
||||
src="/images/auth-ui/large--dark.svg"
|
||||
className="hidden w-4 text-red-900 dark:block"
|
||||
/>
|
||||
<img
|
||||
src="/images/auth-ui/large--light.svg"
|
||||
className="block w-4 text-red-900 dark:hidden"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-scale-1200 text-base">Social Auth Layout</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setLayout('horizontal')}
|
||||
className={[
|
||||
'dark:bg-scale-400 bg-scale-100 dark:border-scale-500 border-scale-500 flex h-10 w-10 items-center justify-center rounded-full border transition hover:scale-105 ',
|
||||
layout === 'horizontal'
|
||||
? 'ring-scale-400 border-scale-800 border-2 ring-2 dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
<MenuIcon className="text-scale-900 dark:text-scale-1100 w-6 rotate-90" />
|
||||
</button>{' '}
|
||||
<button
|
||||
onClick={() => setLayout('vertical')}
|
||||
className={[
|
||||
'dark:bg-scale-400 bg-scale-100 dark:border-scale-500 border-scale-500 flex h-10 w-10 items-center justify-center rounded-full border transition hover:scale-105 ',
|
||||
layout === 'vertical'
|
||||
? 'ring-scale-400 border-scale-800 border-2 ring-2 dark:ring-white'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
<MenuIcon className="text-scale-900 dark:text-scale-1100 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthWidgetSection
|
||||
@@ -14,7 +14,7 @@ export default function LaunchHero() {
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<Link href="#launch-week-5-day-2">
|
||||
<Link href="#launch-week-5-day-5">
|
||||
<Button type="primary" size="small" className="text-white">
|
||||
Latest release
|
||||
</Button>
|
||||
|
||||
@@ -5,28 +5,18 @@ import { Article } from '../types'
|
||||
const ArticleButtonListItem = (props: Article) => {
|
||||
return (
|
||||
<Link href={props.url}>
|
||||
<div className="group mr-2 mb-2">
|
||||
<button
|
||||
className="
|
||||
|
||||
text-scale-1200
|
||||
flex gap-3
|
||||
|
||||
transition"
|
||||
>
|
||||
<div className="w-10">
|
||||
<NewspaperIcon strokeWidth={1} />
|
||||
<a className="group mr-2 mb-2">
|
||||
<div className="flex flex-row">
|
||||
<div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-scale-1200 group-hover:text-brand-900 text-left text-base transition">
|
||||
{props.title}
|
||||
</span>
|
||||
<p className="text-scale-1100 text-left text-sm transition">{props.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-start gap-0">
|
||||
<span className="group-hover:text-brand-900 text-left text-base transition">
|
||||
{props.title}
|
||||
</span>
|
||||
<span className="text-scale-1100 text-left text-sm transition">
|
||||
{props.description}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const ProductButtonListItem = (props: Article) => {
|
||||
</div>
|
||||
<div className="flex flex-col items-start gap-0">
|
||||
<span className="group-hover:text-brand-900 text-sm">{props.title}</span>
|
||||
<span className="text-scale-900 text-sm">{props.description}</span>
|
||||
<p className="text-scale-1100 text-left text-sm">{props.description}</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -176,8 +176,9 @@ export const LaunchSection = (props: WeekDayProps) => {
|
||||
{props.shipped && (
|
||||
<div className="flex flex-col gap-12">
|
||||
{props.articles &&
|
||||
props.articles.map((article: Article) => (
|
||||
props.articles.map((article: Article, index) => (
|
||||
<div
|
||||
key={article.url + index}
|
||||
className="
|
||||
dark:bg-scale-300 rounded border bg-white
|
||||
"
|
||||
@@ -186,24 +187,24 @@ export const LaunchSection = (props: WeekDayProps) => {
|
||||
<ArticleButtonListItem {...article} />
|
||||
</div>
|
||||
|
||||
{/* border */}
|
||||
<div className="bg-scale-300 dark:bg-scale-400 h-px w-full"></div>
|
||||
{article.products && (
|
||||
<>
|
||||
{/* border */}
|
||||
<div className="bg-scale-300 dark:bg-scale-400 h-px w-full"></div>
|
||||
|
||||
<div className="flex flex-col gap-6 p-6 px-10 pb-10">
|
||||
<h3 className="text-scale-1100 mb-2">New releases</h3>
|
||||
{article.products &&
|
||||
article.products.map((product: Product) => (
|
||||
<ProductButtonListItem {...product} />
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col gap-6 p-6 px-10 pb-10">
|
||||
<h3 className="text-scale-1100 text-sm">New releases</h3>
|
||||
{article.products &&
|
||||
article.products.map((product: Product, index) => (
|
||||
<ProductButtonListItem key={product.url + index} {...product} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="">
|
||||
{props.products &&
|
||||
props.products.map((product: Product) => <ProductButton {...product} />)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -56,21 +56,152 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"shipped": false,
|
||||
"title": "Security",
|
||||
"shipped": true,
|
||||
"date": "17th Aug 2022",
|
||||
"description": "An update on the ongoing security improvements of Supabase.",
|
||||
"d": 3,
|
||||
"dd": "Wednesday"
|
||||
"dd": "Wednesday",
|
||||
"youtube_id": "6bGQotxisoY",
|
||||
"announcements": [
|
||||
{
|
||||
"title": "Supabase is now SOC2 compliant",
|
||||
"url": "Something",
|
||||
"description": "Outline of the community changes",
|
||||
"type": "soc2"
|
||||
}
|
||||
],
|
||||
"articles": [
|
||||
{
|
||||
"title": "Supabase is SOC2 compliant",
|
||||
"url": "/blog/supabase-soc2",
|
||||
"description": "Supabase is now SOC2 Type 1 compliant. Let’s dig into what that means, and explain the process we went through to get there. If you’re building a SaaS product, this blog post should provide a rough guide to getting your SOC2 certification.",
|
||||
"products": [
|
||||
{
|
||||
"title": "Security portal",
|
||||
"url": "https://security.supabase.com/",
|
||||
"description": "Monitor security at Supabase."
|
||||
},
|
||||
{
|
||||
"title": "SOC 2 Document",
|
||||
"url": "https://security.supabase.com/",
|
||||
"description": "Request the SOC 2 Type I document through the Security Portal."
|
||||
},
|
||||
{
|
||||
"title": "DPA Document",
|
||||
"url": "https://security.supabase.com/",
|
||||
"description": "Request Data Processing Agreement document through the Security Portal."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"shipped": false,
|
||||
"title": "Realtime: Multiplayer Edition",
|
||||
"shipped": true,
|
||||
"date": "18th Aug 2022",
|
||||
"description": "Announcing the general availability of Realtime's Broadcast and Presence.",
|
||||
"d": 4,
|
||||
"dd": "Thursday"
|
||||
"dd": "Thursday",
|
||||
"youtube_id": "CGZr5tybW18",
|
||||
"articles": [
|
||||
{
|
||||
"title": "Realtime: Multiplayer Edition",
|
||||
"url": "/blog/supabase-realtime-multiplayer-general-availability",
|
||||
"description": "Origin story of Realtime, Broadcast and Presence features with examples, and one more thing.",
|
||||
"products": [
|
||||
{
|
||||
"title": "Realtime Overview",
|
||||
"url": "/docs/guides/realtime",
|
||||
"description": "Realtime Overview"
|
||||
},
|
||||
{
|
||||
"title": "Broadcast Guide",
|
||||
"url": "/docs/guides/realtime/broadcast",
|
||||
"description": "Guide on how to use Broadcast feature"
|
||||
},
|
||||
{
|
||||
"title": "Presence Guide",
|
||||
"url": "/docs/guides/realtime/presence",
|
||||
"description": "Guide on how to use Presence feature"
|
||||
},
|
||||
{
|
||||
"title": "Postgres Changes Guide",
|
||||
"url": "/docs/guides/realtime/postgres-changes",
|
||||
"description": "Guide on how to use Postgres Changes feature"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"shipped": false,
|
||||
"title": "Community and One more thing...",
|
||||
"shipped": true,
|
||||
"date": "19th Aug 2022",
|
||||
"description": "We finish Launch Week 5 with an update on the community and some more product updates.",
|
||||
"d": 5,
|
||||
"dd": "Friday"
|
||||
"dd": "Friday",
|
||||
"youtube_id": "s9UePQjLT0U",
|
||||
"articles": [
|
||||
{
|
||||
"title": "Community Day",
|
||||
"url": "/blog/launch-week-5-community-day",
|
||||
"description": "Outline of the community changes",
|
||||
"products": [
|
||||
{
|
||||
"title": "pg_jsonschema: 0.1.0",
|
||||
"url": "/blog/launch-week-5-community-day#pg_jsonschema",
|
||||
"description": "For our Open Source Spotlight we're hearing from Dmitry Dygalo. "
|
||||
},
|
||||
{
|
||||
"title": "Postgrest v10: Native Types",
|
||||
"url": "/blog/launch-week-5-community-day#postgrest-v10-native-types",
|
||||
"description": "EXPLAIN, Query Planners, Improved Relationship Detection, and Computed relationships."
|
||||
},
|
||||
{
|
||||
"title": "Egghead course",
|
||||
"url": "/blog/launch-week-5-community-day#free-egghead-course-cache-supabase-data-at-the-edge-with-cloudflare-workers-and-kv-storage",
|
||||
"description": "Cache Supabase data at the Edge with Cloudflare Workers and KV Storage."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "One more thing",
|
||||
"url": "/blog/launch-week-5-one-more-thing",
|
||||
"description": "It's never just one more thing...",
|
||||
"products": [
|
||||
{
|
||||
"title": "Supabase Vault",
|
||||
"url": "/blog/supabase-vault",
|
||||
"description": "Postgres extension for managing secrets and encryption inside your database."
|
||||
},
|
||||
{
|
||||
"title": "Auth UI",
|
||||
"url": "/blog/launch-week-5-one-more-thing#auth-ui",
|
||||
"description": "Customizable React UI component for Supabase Auth."
|
||||
},
|
||||
{
|
||||
"title": "Dashboard permissions",
|
||||
"url": "/blog/launch-week-5-one-more-thing#dashboard-permissions",
|
||||
"description": "We've released granular permissions on our Supabase dashboard."
|
||||
},
|
||||
{
|
||||
"title": "JSON schema validation",
|
||||
"url": "/blog/launch-week-5-one-more-thing#json-schema-validation",
|
||||
"description": "We've released a new Postgres extension on the Supabase platform today, pg_jsonschema."
|
||||
},
|
||||
{
|
||||
"title": "pg_graphql v0.4.0",
|
||||
"url": "/blog/launch-week-5-one-more-thing#pg_graphql-v040",
|
||||
"description": "We've released a new version of pg_graphql, our GraphQL extension for Postgres."
|
||||
},
|
||||
{
|
||||
"title": "Auth | Multi Factor Authentication",
|
||||
"url": "/blog/launch-week-5-one-more-thing#multi-factor-authentication",
|
||||
"description": "We've opened early-access signups for Multi-Factor Authentication (MFA)."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -2,5 +2,5 @@
|
||||
"friday_preview": true,
|
||||
"hackathon_preview": true,
|
||||
"ticket_callout": true,
|
||||
"hero_header": "Day 2 shipped"
|
||||
"hero_header": "Day 5 shipped"
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import { Button, Form, Input, Select } from '@supabase/ui'
|
||||
import { useState } from 'react'
|
||||
import countries from '~/data/Countries.json'
|
||||
import supabase from '~/lib/supabase'
|
||||
|
||||
const INITIAL_VALUES = {
|
||||
companyName: '',
|
||||
contactFirstName: '',
|
||||
contactLastName: '',
|
||||
contactEmail: '',
|
||||
contactPhone: '',
|
||||
companySize: '',
|
||||
details: '',
|
||||
country: 'US',
|
||||
}
|
||||
|
||||
const validate = (values: any) => {
|
||||
const errors: any = {}
|
||||
|
||||
if (!values.companyName) {
|
||||
errors.companyName = 'Required'
|
||||
}
|
||||
|
||||
if (!values.contactFirstName) {
|
||||
errors.contactFirstName = 'Required'
|
||||
}
|
||||
|
||||
if (!values.contactLastName) {
|
||||
errors.contactLastName = 'Required'
|
||||
}
|
||||
|
||||
if (!values.contactEmail) {
|
||||
errors.contactEmail = 'Required'
|
||||
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.contactEmail)) {
|
||||
errors.contactEmail = 'Invalid email address'
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
const MfaContactForm = () => {
|
||||
const [formSubmitted, setFormSubmitted] = useState<boolean>(false)
|
||||
|
||||
const handleFormSubmit = async (values: typeof INITIAL_VALUES, { resetForm }: any) => {
|
||||
const { error } = await supabase.from('mfa_early_access_contacts').insert(
|
||||
[
|
||||
{
|
||||
company_name: values.companyName,
|
||||
contact_name: `${values.contactFirstName} ${values.contactLastName}`,
|
||||
contact_first_name: values.contactFirstName,
|
||||
contact_last_name: values.contactLastName,
|
||||
contact_email: values.contactEmail,
|
||||
contact_phone: values.contactPhone,
|
||||
company_size: values.companySize,
|
||||
details: values.details,
|
||||
country: values.country,
|
||||
},
|
||||
],
|
||||
{ returning: 'minimal' }
|
||||
)
|
||||
|
||||
// TODO: handle error
|
||||
console.log('error:', error)
|
||||
if (!error) {
|
||||
resetForm()
|
||||
|
||||
setFormSubmitted(true)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form initialValues={INITIAL_VALUES} validate={validate} onSubmit={handleFormSubmit}>
|
||||
{({ isSubmitting }: any) => (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div>
|
||||
<Input
|
||||
label="Company Name *"
|
||||
id="companyName"
|
||||
name="companyName"
|
||||
layout="vertical"
|
||||
placeholder="Supa Inc."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-4">
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
label="Your First Name *"
|
||||
id="contactFirstName"
|
||||
name="contactFirstName"
|
||||
layout="vertical"
|
||||
placeholder="Jane"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
label="Your Last Name *"
|
||||
id="contactLastName"
|
||||
name="contactLastName"
|
||||
layout="vertical"
|
||||
placeholder="Doe"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
label="Your Business Email *"
|
||||
id="contactEmail"
|
||||
name="contactEmail"
|
||||
layout="vertical"
|
||||
placeholder="janedoe@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select label="Company Size" id="companySize" name="companySize" layout="vertical">
|
||||
<Select.Option value="">{'--'}</Select.Option>
|
||||
<Select.Option value="1-10">1-10 Employees</Select.Option>
|
||||
<Select.Option value="11-50">11-50 Employees</Select.Option>
|
||||
<Select.Option value="51-200">51-200 Employees</Select.Option>
|
||||
<Select.Option value="201-500">201-500 Employees</Select.Option>
|
||||
<Select.Option value="501-1000">501-1000 Employees</Select.Option>
|
||||
<Select.Option value="1001-5000">1001-5000 Employees</Select.Option>
|
||||
<Select.Option value="5001+">5001+ Employees</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
label="Your Phone Number"
|
||||
id="contactPhone"
|
||||
name="contactPhone"
|
||||
layout="vertical"
|
||||
placeholder="+65 1234 1234"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select label="Country / Main Timezone" id="country" name="country" layout="vertical">
|
||||
{countries.map(({ code, name }) => (
|
||||
<Select.Option key={code} value={code}>
|
||||
{name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<Input.TextArea
|
||||
id="details"
|
||||
name="details"
|
||||
label="Additional Details"
|
||||
placeholder="Tell us about your projects, clients, and technology..."
|
||||
rows={10}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex w-full flex-row-reverse pt-4">
|
||||
<Button
|
||||
size="xlarge"
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
htmlType="submit"
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Form>
|
||||
|
||||
{formSubmitted && (
|
||||
<h3 className="h3 mt-12 text-center">Thanks, we'll reach out to you shortly.</h3>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MfaContactForm
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"show": true,
|
||||
"text": "Supabase.js v2 release candidate",
|
||||
"text": "Community Day & One More Thing!",
|
||||
"cta": "Learn more",
|
||||
"link": "/launch-week",
|
||||
"badge": "Day 2"
|
||||
"badge": "Day 5"
|
||||
}
|
||||
@@ -58,6 +58,10 @@
|
||||
{
|
||||
"text": "Privacy Policy",
|
||||
"url": "/docs/company/privacy"
|
||||
},
|
||||
{
|
||||
"text": "DPA",
|
||||
"url": "/legal/dpa"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import Image from 'next/image'
|
||||
import Avatar from '~/components/Avatar'
|
||||
import CodeBlock from '~/components/CodeBlock/CodeBlock'
|
||||
import ImageGrid from '~/components/ImageGrid'
|
||||
import DefaultLayout from '~/components/Layouts/Default'
|
||||
import Quote from '~/components/Quote'
|
||||
|
||||
const ignoreClass = 'ignore-on-export'
|
||||
|
||||
function getComponents(type: any) {
|
||||
const components = {
|
||||
CodeBlock,
|
||||
Quote,
|
||||
Avatar,
|
||||
code: (props: any) => {
|
||||
if (props.className !== ignoreClass) {
|
||||
return <CodeBlock {...props} />
|
||||
} else {
|
||||
return <code {...props} />
|
||||
}
|
||||
},
|
||||
ImageGrid,
|
||||
img: (props: any) => {
|
||||
if (props.className !== ignoreClass) {
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'next-image--dynamic-fill',
|
||||
type === 'blog' && 'to-scale-400 from-scale-500 rounded-lg border bg-gradient-to-r',
|
||||
].join(' ')}
|
||||
>
|
||||
<Image
|
||||
{...props}
|
||||
className={['next-image--dynamic-fill', type === 'blog' && 'rounded-md border'].join(
|
||||
' '
|
||||
)}
|
||||
layout="fill"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return <img {...props} />
|
||||
},
|
||||
}
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
export default function ContentsLayout({ context }: any) {
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<NextSeo {...context.meta} />
|
||||
<MDXProvider components={getComponents(context.type)}>
|
||||
<div className="prose max-w-none">{context.children}</div>
|
||||
</MDXProvider>
|
||||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
@@ -109,7 +109,7 @@
|
||||
"author_id": "thor_schaeff",
|
||||
"author": "Thor Schaeff",
|
||||
"position": "DevRel & DX",
|
||||
"author_url": "https://github.com/thorwebdev",
|
||||
"author_url": "https://twitter.com/thorwebdev",
|
||||
"author_image_url": "https://github.com/thorwebdev.png"
|
||||
},
|
||||
{
|
||||
@@ -175,5 +175,27 @@
|
||||
"position": "Support Engineer",
|
||||
"author_url": "https://github.com/mansueli",
|
||||
"author_image_url": "https://github.com/mansueli.png"
|
||||
},
|
||||
{
|
||||
"author_id": "stas",
|
||||
"author": "Stanislav Muzhyk",
|
||||
"username": "abc3",
|
||||
"position": "Engineering",
|
||||
"author_url": "https://github.com/abc3",
|
||||
"author_image_url": "https://github.com/abc3.png"
|
||||
},
|
||||
{
|
||||
"author_id": "jonmeyers_io",
|
||||
"author": "Jon Meyers",
|
||||
"position": "Developer Advocate",
|
||||
"author_url": "https://twitter.com/jonmeyers_io",
|
||||
"author_image_url": "https://github.com/dijonmusters.png"
|
||||
},
|
||||
{
|
||||
"author_id": "michel",
|
||||
"author": "Michel Pelletier",
|
||||
"position": "Engineering",
|
||||
"author_url": "https://github.com/michelp",
|
||||
"author_image_url": "https://github.com/michelp.png"
|
||||
}
|
||||
]
|
||||
@@ -28,7 +28,7 @@ export const generateRss = (posts: any[]): string => {
|
||||
<lastBuildDate>${dayjs(posts[0].date)
|
||||
.utc()
|
||||
.format('ddd, DD MMM YYYY HH:hh:mm ZZ')}</lastBuildDate>
|
||||
<atom:link href="https://supabase.com/blog/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<atom:link href="https://supabase.com/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
${posts.map(generateRssItem).join('')}
|
||||
</channel>
|
||||
</rss>
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
const withMDX = require('@next/mdx')()
|
||||
const gfm = require('remark-gfm')
|
||||
const slug = require('rehype-slug')
|
||||
const withMDX = require('@next/mdx')({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
remarkPlugins: [gfm],
|
||||
rehypePlugins: [slug],
|
||||
// If you use `MDXProvider`, uncomment the following line.
|
||||
providerImportSource: '@mdx-js/react',
|
||||
},
|
||||
})
|
||||
|
||||
module.exports = withMDX({
|
||||
basePath: '',
|
||||
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
|
||||
|
||||
trailingSlash: false,
|
||||
images: {
|
||||
dangerouslyAllowSVG: true,
|
||||
@@ -18,6 +27,8 @@ module.exports = withMDX({
|
||||
'avatars.githubusercontent.com',
|
||||
'colab.research.google.com',
|
||||
'api.producthunt.com',
|
||||
'https://s3-us-west-2.amazonaws.com',
|
||||
's3-us-west-2.amazonaws.com',
|
||||
],
|
||||
},
|
||||
async headers() {
|
||||
@@ -1418,6 +1429,11 @@ module.exports = withMDX({
|
||||
source: '/docs/guides/local-development',
|
||||
destination: '/docs/guides/cli/local-development',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/realtime/overview',
|
||||
destination: '/docs/guides/realtime',
|
||||
},
|
||||
// V2 redirects
|
||||
// {
|
||||
// permanent: true,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@next/mdx": "^10.0.7",
|
||||
"@supabase/auth-ui-react": "^0.1.6",
|
||||
"@supabase/supabase-js": "^1.6.0",
|
||||
"@supabase/ui": "v0.37.0-alpha.80",
|
||||
"classnames": "^2.3.1",
|
||||
@@ -66,7 +67,7 @@
|
||||
"postcss": "^8.4.7",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "^2.2.1",
|
||||
"tailwindcss": "^3.0.23"
|
||||
"tailwindcss": "^3.1.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -4,11 +4,8 @@ import {
|
||||
IconArrowUpRight,
|
||||
IconBriefcase,
|
||||
IconEye,
|
||||
IconKey,
|
||||
IconLink,
|
||||
IconShield,
|
||||
IconX,
|
||||
Space,
|
||||
} from '@supabase/ui'
|
||||
import ApiExamples from 'data/products/auth/auth-api-examples'
|
||||
import AuthSqlRulesExamples from 'data/products/auth/auth-sql-rules-examples'
|
||||
@@ -17,14 +14,13 @@ import { NextSeo } from 'next-seo'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import AuthComponentExample from '~/components/AuthWidget/AuthComponentExample'
|
||||
import AuthWidgetSection from '~/components/AuthWidget/AuthWidgetSection'
|
||||
import SplitCodeBlockCarousel from '~/components/Carousels/SplitCodeBlockCarousel'
|
||||
import CTABanner from '~/components/CTABanner'
|
||||
import FeatureColumn from '~/components/FeatureColumn'
|
||||
import FloatingIcons from '~/components/FloatingIcons'
|
||||
import DefaultLayout from '~/components/Layouts/Default'
|
||||
import SectionContainer from '~/components/Layouts/SectionContainer'
|
||||
import ProductIcon from '~/components/ProductIcon'
|
||||
import APISection from '~/components/Sections/APISection'
|
||||
import GithubExamples from '~/components/Sections/GithubExamples'
|
||||
import ProductHeader from '~/components/Sections/ProductHeader'
|
||||
@@ -218,7 +214,7 @@ function AuthPage() {
|
||||
</div>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="grid grid-cols-12 lg:gap-16">
|
||||
<div className="grid grid-cols-12 lg:mt-16 lg:gap-16">
|
||||
<div className="col-span-12 mb-8 lg:col-span-5">
|
||||
<h2 className="h3">User permissions without the middleware</h2>
|
||||
|
||||
@@ -246,62 +242,8 @@ function AuthPage() {
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
{/* <SectionContainer>
|
||||
<div className="grid grid-cols-12 lg:gap-16">
|
||||
<div className="order-last col-span-12 lg:order-first lg:col-span-6 mt-8 lg:mt-0">
|
||||
<AuthComponentExample />
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-6 lg:col-start-7 xl:col-span-4 xl:col-start-8">
|
||||
<div className="mb-4 flex items-center space-x-2">
|
||||
<div className="w-8 h-8 rounded-md bg-gray-900 dark:bg-white text-white dark:text-gray-900 flex justify-center items-center">
|
||||
<ProductIcon icon={Solutions['authentication'].icon} />
|
||||
</div>
|
||||
<p className="m-0">
|
||||
<IconX />
|
||||
</p>
|
||||
<img className="w-8" src={`${basePath}/images/product/auth/react-icon.svg`} />
|
||||
</div>
|
||||
<AuthWidgetSection />
|
||||
|
||||
<h2 className="h3">React Auth</h2>
|
||||
|
||||
<p className="p text-base lg:text-lg">
|
||||
Pre-built auth widgets to get started in minutes.
|
||||
</p>
|
||||
<p className="p">
|
||||
Supabase provides React libraries which handle common scenarios, including logging
|
||||
in, signing up, magic link and forgot password forms.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href="https://github.com/supabase/ui#using-supabase-ui-auth"
|
||||
as="https://github.com/supabase/ui#using-supabase-ui-auth"
|
||||
>
|
||||
<a>
|
||||
<Button size="small" type="default" className="mt-4" icon={<IconArrowUpRight />}>
|
||||
Explore documentation
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<div className="grid grid-cols-12 md:gap-8 lg:gap-0 xl:gap-16 mt-8">
|
||||
<div className="col-span-12 lg:col-span-12 xl:col-span-4">
|
||||
<FeatureColumn
|
||||
icon={<IconBriefcase />}
|
||||
title="Social login support"
|
||||
text="Support for social logins are built in and the component "
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-12 xl:col-span-4">
|
||||
<FeatureColumn
|
||||
icon={<IconEye />}
|
||||
title="User context hooks"
|
||||
text="Access the auth status from any component."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer> */}
|
||||
<CTABanner />
|
||||
</DefaultLayout>
|
||||
</>
|
||||
|
||||
@@ -237,10 +237,10 @@ function BlogPostPage(props: any) {
|
||||
<p>•</p>
|
||||
<p>{generateReadingTime(props.blog.content.renderedOutput)}</p>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col gap-3 pt-6 md:flex-row md:gap-0 lg:gap-3">
|
||||
{author.map((author: any) => {
|
||||
return (
|
||||
<div className="mt-6 mb-8 mr-4 w-max lg:mb-0">
|
||||
<div className="mr-4 w-max">
|
||||
<Link href={author.author_url}>
|
||||
<a className="cursor-pointer">
|
||||
<div className="flex items-center gap-3">
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { NextSeo } from 'next-seo'
|
||||
import { useRouter } from 'next/router'
|
||||
import DefaultLayout from '~/components/Layouts/Default'
|
||||
import MfaContactForm from '~/components/MfaContactForm'
|
||||
|
||||
const meta_title = 'MFA early access | Supabase'
|
||||
const meta_description = ''
|
||||
|
||||
const EnterpriseContactPage = () => {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<NextSeo
|
||||
title={meta_title}
|
||||
description={meta_description}
|
||||
openGraph={{
|
||||
title: meta_title,
|
||||
description: meta_description,
|
||||
url: `https://supabase.com/${router.pathname}`,
|
||||
images: [
|
||||
{
|
||||
url: `https://supabase.com/images/og/og-image.jpg`,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="mx-auto my-16 max-w-xl px-4 md:my-20 lg:my-24 xl:my-32">
|
||||
<h2 className="h2 block pb-16 text-center">MFA Early access</h2>
|
||||
|
||||
<MfaContactForm />
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default EnterpriseContactPage
|
||||
@@ -33,7 +33,7 @@ const featureBlocks = [
|
||||
icon: <IconCode strokeWidth={1.5} />,
|
||||
},
|
||||
{
|
||||
title: 'Async triggers',
|
||||
title: 'Database webhooks',
|
||||
description: 'Invoke Edge Functions based on any event in your database',
|
||||
highlightLines: '28',
|
||||
icon: <IconRefreshCcw strokeWidth={1.5} />,
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function launchweek() {
|
||||
{days.map((item: WeekDayProps, i) => {
|
||||
return (
|
||||
<LaunchSection
|
||||
key={'launchweek-item ' + item.title}
|
||||
key={'launchweek-item ' + (item.title || i)}
|
||||
{...item}
|
||||
index={i}
|
||||
shippingHasStarted={shippingHasStarted}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Button } from '@supabase/ui'
|
||||
import CTABanner from 'components/CTABanner/index'
|
||||
import Link from 'next/link'
|
||||
import Layout from '~/components/Layouts/Default'
|
||||
import SectionContainer from '~/components/Layouts/SectionContainer'
|
||||
|
||||
const DPA = () => {
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<SectionContainer>
|
||||
<div className="mx-auto grid max-w-2xl grid-cols-12 rounded-lg">
|
||||
<div className="col-span-12 flex items-center lg:col-span-12">
|
||||
<div className="prose flex flex-col space-y-8 p-16">
|
||||
<h1 className="text-center text-5xl">DPA</h1>
|
||||
<p>
|
||||
We have a long-standing commitment to customer privacy and data protection, and as
|
||||
part of that commitment we have prepared a pre-signed Data Processing Addendum
|
||||
("DPA").
|
||||
</p>
|
||||
|
||||
<p>You can download the latest DPA document through our security portal.</p>
|
||||
<div>
|
||||
<Link href="https://security.supabase.com">
|
||||
<Button size="medium" type="default">
|
||||
Security portal
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
<CTABanner />
|
||||
</Layout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DPA
|
||||
@@ -0,0 +1,140 @@
|
||||
import {
|
||||
KeyIcon,
|
||||
LinkIcon,
|
||||
UserGroupIcon,
|
||||
ShieldCheckIcon,
|
||||
RewindIcon,
|
||||
CreditCardIcon,
|
||||
ClipboardCheckIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import { Button, IconGitHub } from '@supabase/ui'
|
||||
import Layout from '../layouts/Layout'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const meta = {
|
||||
type: 'lp',
|
||||
title: 'Security at Supabase',
|
||||
description:
|
||||
'Supabase is trusted by thousands of developers for building and deploying secure applications.',
|
||||
}
|
||||
|
||||
export const Section = ({ children, icon, img }) => (
|
||||
<div>
|
||||
{icon && (
|
||||
<div className="bordershadow-scale-500 not-prose dark:bg-scale-400 -mb-4 flex h-10 w-10 items-center justify-center rounded-full bg-white">
|
||||
<figure className="w-5">{icon}</figure>
|
||||
</div>
|
||||
)}
|
||||
{img && <div className="-mb-4 flex h-12 w-12 items-center justify-center">{img}</div>}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
<div className="container mx-auto px-8 sm:px-16 xl:px-20 grid grid-cols-12 items-center my-16">
|
||||
<div className="col-span-12 lg:col-span-6">
|
||||
<h1>Security at Supabase</h1>
|
||||
<h2 className="text-xl text-scale-1100 max-w-xl">
|
||||
Supabase is trusted by thousands of developers for building and deploying secure applications.
|
||||
</h2>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-5 lg:col-start-8">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-8 sm:px-16 xl:px-20 mb-16">
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-16">
|
||||
|
||||
<Section icon={<ShieldCheckIcon strokeWidth={1}/>}>
|
||||
|
||||
### SOC 2
|
||||
|
||||
Supabase is SOC2 Type 1 compliant. Enterprise customers can request a copy of our SOC2 through our [Security Portal](https://security.supabase.com).
|
||||
|
||||
<div className="w-16">
|
||||
<img src="/images/security/21972-312_SOC_NonCPA.png" />
|
||||
</div>
|
||||
|
||||
</Section>
|
||||
<Section icon={<KeyIcon strokeWidth={1}/>}>
|
||||
|
||||
### Data Encryption
|
||||
|
||||
All customer data is encrypted at REST with AES-256 and in transit via TLS.
|
||||
|
||||
Sensitive information like access tokens and keys are encrypted at the application level before they are stored in the database.
|
||||
|
||||
</Section>
|
||||
|
||||
<Section icon={<IconGitHub size={19} />}>
|
||||
|
||||
### Github security integration
|
||||
|
||||
We have [partnered with GitHub](https://github.blog/changelog/2022-03-28-supabase-is-now-a-github-secret-scanning-partner/) to scan for Supabase service role API keys. If any Supabase API keys are pushed to GitHub, they are automatically revoked.
|
||||
|
||||
</Section>
|
||||
|
||||
<Section icon={<UserGroupIcon strokeWidth={1}/>}>
|
||||
|
||||
### Role-based access control
|
||||
|
||||
Members of organizations in Supabase can be granted access to specific resources.
|
||||
|
||||
</Section>
|
||||
|
||||
<Section icon={<RewindIcon strokeWidth={1}/>}>
|
||||
|
||||
### Backups
|
||||
|
||||
All customer databases are backed up every day.
|
||||
|
||||
Enterprise customers have access to Point in Time Recovery which enables restoring the database to any point in time.
|
||||
|
||||
</Section>
|
||||
|
||||
<Section icon={<CreditCardIcon strokeWidth={1}/>}>
|
||||
|
||||
### Payment processing
|
||||
|
||||
Supabase uses [Stripe](https://stripe.com) to process payments and does not store personal credit card information for any of our customers.
|
||||
|
||||
Stripe is a certified PCI Service Provider Level 1, which is the highest level of certification in the payments industry.
|
||||
|
||||
</Section>
|
||||
|
||||
<Section icon={<ClipboardCheckIcon strokeWidth={1}/>}>
|
||||
|
||||
### Vulnerability Management
|
||||
|
||||
Supabase works with industry experts to conduct regular penetration tests.
|
||||
|
||||
In addition to internal security reviews, we use various tools to scan our code for vulnerabilities including [GitHub](https://github.com), [Vanta](https://www.vanta.com/), and [Snyk](https://snyk.io/).
|
||||
|
||||
</Section>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<div className="container mx-auto pb-24 pt-1 px-8 sm:px-16 xl:px-20">
|
||||
<div className="max-w-xl">
|
||||
|
||||
<h3 className="text-3xl">Security Portal</h3>
|
||||
|
||||
Access Supabase’s security and compliance documents on our Security Portal, such as
|
||||
penetration testing and audit reports.
|
||||
|
||||
<Link passHref href="https://security.supabase.com">
|
||||
<Button type="default" size="medium" as="a" className="no-underline" target="_blank">
|
||||
Security Portal
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export default (context) => <Layout meta={meta} children={context.children} context={context} />
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M6.5,.5C3.19,.5,.5,3.19,.5,6.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 418 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M6.5,.5C3.19,.5,.5,3.19,.5,6.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 418 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M.5,6.5V3.7C.5,1.93,1.93,.5,3.7,.5h2.8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 426 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M.5,6.5V3.7C.5,1.93,1.93,.5,3.7,.5h2.8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 426 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M.5,6.5V2.37C.5,1.34,1.34,.5,2.37,.5H6.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 428 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path class="cls-1" d="M.5,6.5V2.37C.5,1.34,1.34,.5,2.37,.5H6.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 621 KiB |
|
After Width: | Height: | Size: 197 KiB |
|
After Width: | Height: | Size: 974 KiB |
|
After Width: | Height: | Size: 269 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 237 KiB |
|
After Width: | Height: | Size: 522 KiB |
|
After Width: | Height: | Size: 243 KiB |
|
After Width: | Height: | Size: 115 KiB |