Merge pull request #9885 from supabase/master

Prod deploy Dashboard
This commit is contained in:
Joshen Lim authored and GitHub committed 2022-10-27 13:07:33 +07:00
commit e031dcc3cd
514 files changed
+49017 -34686

No files matched your search

+4 -4
View File
@@ -1,16 +1,16 @@
---
slug: /
sidebar_position: 1
sidebar_label: Supabase API
sidebar_label: Management API
---
# Supabase API
# Management API
The Supabase API allows you to manage your projects programmatically.
The Management API allows you to manage your projects programmatically.
## Status
The Supabase API is in `beta`. It is usable in it's current state, but it's likely that there will be breaking changes.
The Management API is in `beta`. It is usable in it's current state, but it's likely that there will be breaking changes.
## Authentication
+2 -2
View File
@@ -25,5 +25,5 @@ The CLI is still under development, but it contains all the functionality for wo
- [Install the Supabase CLI](/docs/guides/cli)
- [Source code](https://github.com/supabase/cli)
- [Known bugs and issues](https://github.com/supabase/cli/issues)
- [Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
- [The CLI team announcing CLI V1 and Admin API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28)
- [Supabase CLI v1 and Management API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
- [The CLI team announcing CLI V1 and Management API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28)
+30 -1
View File
@@ -378,7 +378,7 @@ const userListener = supabase.from('users')
<TabItem value="2.x">
```ts
const userListener = supabase.channel('public:user')
const userListener = supabase.channel('all-users-changes')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'user' },
@@ -412,3 +412,32 @@ supabase.removeChannel(userListener)
```
</TabItem>
</Tabs>
#### onOpen
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
supabase.realtime.onOpen(() => console.log('Connected to socket'))
```
</TabItem>
<TabItem value="2.x">
```ts
supabase.channel('any')
.subscribe((status) => {
if (status === 'SUBSCRIBED') {
console.log('Connected to channel')
}
})
```
</TabItem>
</Tabs>
@@ -8,13 +8,29 @@ id: typescript-support
## Generating types
You can use our CLI to generate types:
You can use the [Supabase CLI](/docs/guides/cli) to generate types directly from your Postgres database’s schema:
### Generate types from a remote database
Install the [Supabase CLI](/docs/guides/cli#installation) locally, and then run:
```bash
supabase login
supabase projects list
supabase gen types typescript --project-id <project_id> > lib/database.types.ts
```
### Generate types from a local database
Set up your [local development environment](/docs/guides/cli/local-development), and then run:
```bash
supabase start
supabase gen types typescript --local > lib/database.types.ts
```
For additional methods, see the [CLI Reference Docs](/docs/reference/cli/usage#supabase-gen-types).
These types are generated directly from your database. Given a table `public.movies`, the definition will provide the following data:
```ts
+5 -7
View File
@@ -1,6 +1,6 @@
---
id: api
title: APIs
title: Data APIs
description: Auto-generating and Realtime APIs.
sidebar_label: Overview
---
@@ -9,9 +9,7 @@ import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import useBaseUrl from '@docusaurus/useBaseUrl'
## Overview
Supabase generates three types of API directly from your database schema.
Supabase auto-generates three types of API directly from your database schema.
- REST - interact with your database through a restful interface.
- Realtime - listen to database changes.
@@ -25,7 +23,7 @@ The APIs are:
- **Fast.** <br />Our benchmarks for basic reads are more than 300% faster than Firebase. The API is a very thin layer on top of Postgres, which does most of the heavy lifting.
- **Scalable.** <br />The API can serve thousands of simultaneous requests, and works well for Serverless workloads.
### REST API {#rest-api-overview}
## REST API {#rest-api-overview}
Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres.
It provides everything you need from a CRUD API:
@@ -45,7 +43,7 @@ It provides everything you need from a CRUD API:
></iframe>
</div>
### GraphQL API {#graphql-api-overview}
## GraphQL API {#graphql-api-overview}
:::note
@@ -55,7 +53,7 @@ GraphQL is in Beta, and may have breaking changes. It is only available on self-
GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/pg-graphql), an open source PostgreSQL extension for GraphQL.
### Realtime API {#realtime-api-overview}
## Realtime API {#realtime-api-overview}
Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets.
Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications.
@@ -16,12 +16,9 @@ Setting up Email logins for your Supabase application.
## Configure email settings
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL`
- Under `Email Auth` turn `Enable Email Signup` to ON
- Click `Save`
1. Go to the [Authentication Settings](https://app.supabase.com/project/_/auth/settings) page in the Dashboard.
1. For **Site URL**, enter the final (hosted) URL of your app.
1. Under Auth Providers, **enable email provider**.
:::note Self hosting
@@ -19,12 +19,9 @@ Setting up Magic Link logins for your Supabase application.
## Add Magic Link into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `Email Auth` turn `Enable Email Signup` to ON
- Click `Save`
1. Go to the [Authentication Settings](https://app.supabase.com/project/_/auth/settings) page in the Dashboard.
1. For **Site URL**, enter the final (hosted) URL of your app.
1. Under Auth Providers, **enable email provider**.
## Add login code to your client app
@@ -49,42 +49,6 @@ Returns the ID of the user making the request.
Returns the JWT of the user making the request.
### `auth.role()`
:::caution
Deprecated
:::
The `auth.role()` function has been deprecated in favour of using the `TO` field, natively supported within Postgres.
```sql
-- DEPRECATED
create policy "Public profiles are viewable by everyone."
on profiles for select using (
auth.role() = 'authenticated' or auth.role() = 'anon'
);
-- RECOMMENDED
create policy "Public profiles are viewable by everyone."
on profiles for select
to authenticated, anon
using (
true
);
```
### `auth.email()`
:::caution
Deprecated. Use `auth.jwt() ->> 'email'` instead.
:::
Returns the email of the user making the request.
## Examples
Here are some examples to show you the power of PostgreSQL's RLS.
@@ -361,3 +325,41 @@ Tip: Make sure to enable RLS for all your tables, so that your tables are inacce
Supabase provides special "Service" keys, which can be used to bypass all RLS.
These should never be used in the browser or exposed to customers, but they are useful for administrative tasks.
## Deprecated features
We have deprecate some functions to ensure better performance and extensibilty of RLS policies.
### `auth.role()`
:::caution
Deprecated: The `auth.role()` function has been deprecated in favour of using the `TO` field, natively supported within Postgres.
:::
```sql
-- DEPRECATED
create policy "Public profiles are viewable by everyone."
on profiles for select using (
auth.role() = 'authenticated' or auth.role() = 'anon'
);
-- RECOMMENDED
create policy "Public profiles are viewable by everyone."
on profiles for select
to authenticated, anon
using (
true
);
```
### `auth.email()`
:::caution
Deprecated. Use `auth.jwt() ->> 'email'` instead.
:::
Returns the email of the user making the request.
@@ -12,11 +12,11 @@ Supabase provides several options for programmatically connecting to your Postgr
- Direct connections using Postgres' standard connection system.
- Connection pooling using PgBouncer.
### API vs Direct vs Pooling
### Direct vs Pooling vs API
- The API is an auto-generated REST interface. You should use this for all browser and application interactions.
- A "direct connection" is when a connection is made to the database using Postgres' native connection implementation. You should use this for tools which are always alive - usually installed on a long-running server.
- A "connection pool" is a system (external to Postgres) which keeps connections "open". You should use this for serverless functions and tools which disconnect from the database frequently.
- The API is an auto-generated REST interface. You should use this for all browser and application interactions. The API server internally handles a connection pool.
Why would you use a connection pool? Primarily because the way that Postgres handles connections isn't very scalable for a large number of _temporary_ connections.
You can use these simple questions to determine which connection method to use:
@@ -0,0 +1,74 @@
---
id: webhooks
title: 'Database Webhooks'
description: Trigger external payloads on database events.
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Database Webhooks allow you to send real-time data from your database to another system whenever a table event occurs.
You can hook into three table events: `INSERT`, `UPDATE`, and `DELETE`. All events are fired _after_ a database row is changed.
Database Webhooks are very similar to triggers, and that's because Database Webhooks are just a convenience wrapper around triggers
using the [pg_net](/docs/guides/database/extensions/pgnet) extension. This extension is asynchronous, and therefore will not block your database changes for long-running network requests.
This video demonstrates how you can create a new customer in Stripe each time a row is inserted into a `profiles` table:
:::note
Database Webhooks were previously known as Function Hooks.
:::
<div class="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/codAs9-NeHM"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
## Creating a webhook
1. Create a new [Database Webhook](https://app.supabase.com/project/_/database/hooks) in the Dashboard.
1. Give your Webhook a name.
1. Select the table you want to hook into.
1. Select one or more events (table inserts, updates, or deletes) you want to hook into.
We currently support HTTP webhooks. These are sent as a `POST` request with a JSON payload.
## Payload
The payload is automatically generated from the underlying table record:
```typescript
type InsertPayload = {
type: 'INSERT'
table: string
schema: string
record: TableRecord<T>
old_record: null
}
type UpdatePayload = {
type: 'UPDATE'
table: string
schema: string
record: TableRecord<T>
old_record: TableRecord<T>
}
type DeletePayload = {
type: 'DELETE'
table: string
schema: string
record: null
old_record: TableRecord<T>
}
```
## Resources
- [pg_net](/docs/guides/database/extensions/pgnet): an async networking extension for PostgreSQL
@@ -0,0 +1,99 @@
---
id: pgcron
title: 'pg_cron: Job Scheduling'
description: 'pgnet: a simple cron-based job scheduler for PostgreSQL that runs inside the database.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
The `pg_cron` extension is a simple cron-based job scheduler for PostgreSQL that runs inside the database.
## Usage
### Enable the extension
<Tabs
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
2. Click on **Extensions** in the sidebar.
3. Search for "pg_cron" and enable the extension.
</TabItem>
<TabItem value="sql">
```sql
-- Example: enable the "pg_cron" extension
create extension pg_cron with schema extensions;
-- If you're planning to use a non-superuser role to schedule jobs,
-- ensure that they are granted access to the cron schema and its underlying objects beforehand.
-- Failure to do so would result in jobs by these roles to not run at all.
grant usage on schema cron to {{DB user}};
grant all privileges on all tables in schema cron to {{DB user}};
-- Example: disable the "pg_cron" extension
drop extension if exists pg_cron;
```
</TabItem>
</Tabs>
### Syntax
The schedule uses the standard cron syntax, in which \* means "run every time period", and a specific number means "but only at this time":
```bash
┌───────────── min (0 - 59)
│ ┌────────────── hour (0 - 23)
│ │ ┌─────────────── day of month (1 - 31)
│ │ │ ┌──────────────── month (1 - 12)
│ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
│ │ │ │ │ Saturday, or use names; 7 is also Sunday)
│ │ │ │ │
│ │ │ │ │
* * * * *
```
## Examples
### Delete data every week
Delete old data on Saturday at 3:30am (GMT):
```sql
select cron.schedule (
'webhook-every-minute', -- name of the cron job
'* * * * *', -- every minute
$$ delete from events where event_time < now() - interval '1 week' $$
);
```
### Run a vacuum every day
Vacuum every day at 3:00am (GMT)
```sql
SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
```
### Unschedule a job
Unschedules a job called `'nightly-vacuum'`
```sql
SELECT cron.unschedule('nightly-vacuum');
```
## Resources
- [pg_cron GitHub Repository](https://github.com/citusdata/pg_cron)
@@ -0,0 +1,254 @@
---
id: pgnet
title: 'pg_net: Async Networking'
description: 'pg_net: an async networking extension for PostgreSQL.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
:::caution
The pg_net API is in beta. Functions signatures may change.
:::
[pg_net](https://github.com/supabase/pg_net/) is a PostgreSQL extension exposing a SQL interface for async networking with a focus on scalability and UX.
It differs from the `http` extension in that it is asynchronous by default. This makes it useful in blocking functions (like triggers).
## Usage
### Enable the extension
<Tabs
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
2. Click on **Extensions** in the sidebar.
3. Search for "pg_net" and enable the extension.
</TabItem>
<TabItem value="sql">
```sql
-- Example: enable the "pg_net" extension
create schema if not exists net;
create extension pg_net with schema net;
-- Example: disable the "plv8" extension
drop extension if exists pg_net;
drop schema net;
```
Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
To disable an extension, call `drop extension`.
Procedural languages are automatically installed within `pg_catalog`, so you don't need to specify a schema.
</TabItem>
</Tabs>
## `http_get` {#http_get}
Creates an HTTP GET request returning the request's ID. HTTP requests are not started until the transaction is committed.
### Signature
:::caution
This is a Postgres SECURITY DEFINER function.
:::
```sql
net.http_get(
-- url for the request
url text,
-- key/value pairs to be url encoded and appended to the `url`
params jsonb default '{}'::jsonb,
-- key/values to be included in request headers
headers jsonb default '{}'::jsonb,
-- WARNING: this is currently ignored, so there is no timeout
-- the maximum number of milliseconds the request may take before being cancelled
timeout_milliseconds int default 1000
)
-- request_id reference
returns bigint
strict
volatile
parallel safe
language plpgsql
```
### Usage
```sql
select net.http_get('https://news.ycombinator.com') as request_id;
request_id
----------
1
(1 row)
```
After triggering `http_get`, use [`http_get_result`](#http_get_result) to get the result of the request.
## `http_post` {#http_post}
Creates an HTTP POST request with a JSON body, returning the request's ID. HTTP requests are not started until the transaction is committed.
The body's character set encoding matches the database's `server_encoding` setting.
### Signature
:::caution
This is a Postgres SECURITY DEFINER function
:::
```sql
net.http_post(
-- url for the request
url text,
-- body of the POST request
body jsonb default '{}'::jsonb,
-- key/value pairs to be url encoded and appended to the `url`
params jsonb default '{}'::jsonb,
-- key/values to be included in request headers
headers jsonb default '{"Content-Type": "application/json"}'::jsonb,
-- WARNING: this is currently ignored, so there is no timeout
-- the maximum number of milliseconds the request may take before being cancelled
timeout_milliseconds int default 1000
)
-- request_id reference
returns bigint
volatile
parallel safe
language plpgsql
```
### Usage
```sql
select
net.http_post(
url:='https://httpbin.org/post',
body:='{"hello": "world"}'::jsonb
) as request_id;
request_id
----------
1
(1 row)
```
After triggering `http_post`, use [`http_get_result`](#http_get_result) to get the result of the request.
## `http_collect_response` {#http_collect_response}
Given a `request_id` reference, retrieves the response.
When `async:=false` is set it is recommended that [statement_timeout](https://www.postgresql.org/docs/13/runtime-config-client.html) is set for the maximum amount of time the caller is willing to wait in case the response is slow to populate.
### Signature
:::caution
This is a Postgres SECURITY DEFINER function
:::
```sql
net.http_collect_response(
-- request_id reference
request_id bigint,
-- when `true`, return immediately. when `false` wait for the request to complete before returning
async bool default true
)
-- http response composite wrapped in a result type
returns net.http_response_result
strict
volatile
parallel safe
```
### Usage
:::caution
`net.http_collect_response` must be in a separate transaction from the calls to `net.http_<method>`
:::
```sql
select
net.http_post(
url:='https://httpbin.org/post',
body:='{"hello": "world"}'::jsonb
) as request_id;
request_id
----------
1
(1 row)
select * from net.http_collect_response(1, async:=false);
status | message | response
--------+---------+----------
SUCCESS ok (
status_code := 200,
headers := '{"date": ...}',
body := '{"args": ...}'
)::net.http_response_result
select
(response).body::json
from
net.http_collect_response(request_id:=1);
body
-------------------------------------------------------------------
{
"args": {},
"data": "{\"hello\": \"world\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "18",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "pg_net/0.2",
"X-Amzn-Trace-Id": "Root=1-61031a5c-7e1afeae69bffa8614d8e48e"
},
"json": {
"hello": "world"
},
"origin": "135.63.38.488",
"url": "https://httpbin.org/post"
}
(1 row)
```
Where `response` is a composite:
```sql
status_code integer
headers jsonb
body text
```
Possible values for `net.http_response_result.status` are `('PENDING', 'SUCCESS', 'ERROR')`
## Resources
- Source code: [github.com/supabase/pg_net](https://github.com/supabase/pg_net/)
- Official Docs: [supabase.github.io/pg_net](https://supabase.github.io/pg_net/)
@@ -245,7 +245,7 @@ For example, if you wanted to load a CSV file into your movies table:
You would [connect](../../guides/database/connecting-to-postgres#direct-connections) to your database directly and load the file with the COPY command:
```bash
psql -h DATABASE_URL -p 5432 postgres -U postgres \
psql -h DATABASE_URL -p 5432 -d postgres -U postgres \
-c "COPY movies FROM './movies.csv';"
```
+5 -5
View File
@@ -133,7 +133,7 @@ Globally distributed TypeScript functions to execute custom business logic. [Doc
Use our CLI to develop your project locally and deploy to the Supabase Platform. [Docs](/docs/reference/cli).
### Admin API
### Management API
Manage your projects programmatically. [Docs](/docs/reference/api).
@@ -154,9 +154,9 @@ Both Postgres and the Supabase Platform are production-ready. Some tools we offe
| Database | Point-in-Time Recovery | `alpha` |
| Database | Vault | `alpha` |
| Studio | | `GA` |
| Realtime | Postgres CDC | `beta` |
| Realtime | Broadcast | `alpha` |
| Realtime | Presence | `alpha` |
| Realtime | Postgres CDC | `GA` |
| Realtime | Broadcast | `beta` |
| Realtime | Presence | `beta` |
| Storage | Backend (S3) | `GA` |
| Storage | API | `beta` |
| Storage | CDN | `beta` |
@@ -165,7 +165,7 @@ Both Postgres and the Supabase Platform are production-ready. Some tools we offe
| Auth | Passwordless | `beta` |
| Auth | Next.js Auth Helpers | `alpha` |
| Auth | SvelteKit Auth Helpers | `alpha` |
| Admin API | | `beta` |
| Management API | | `beta` |
| CLI | | `beta` |
| Client Library: JavaScript | | `GA` |
| Client Library: Dart | | `beta` |
+4 -1
View File
@@ -263,6 +263,10 @@ serve(async (req) => {
})
```
### Using HTTP Methods
Edge Functions supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. A function can be designed to perform different actions based on a request's HTTP method. See the [example on building a RESTful service](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/restful-tasks) to learn how to handle different HTTP methods in your function.
## Limitations
- Deno Deploy limitations
@@ -270,5 +274,4 @@ serve(async (req) => {
- Cannot write to File System
- Edge Functions
- Local development - only one function at a time
- Supabase Functions only supports `POST`, `OPTIONS`, and `GET` requests.
- Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`).
@@ -26,6 +26,16 @@ const examples = [
description: 'Full example for using Supabase and Stripe, with Flutter.',
href: 'https://github.com/supabase-community/flutter-stripe-payments-with-supabase-functions',
},
{
name: 'Building a RESTful Service API',
description: 'Learn how to use HTTP methods and paths to build a RESTful service for managing tasks.',
href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/restful-tasks/index.ts',
},
{
name: 'Working with Supabase Storage',
description: 'An example on reading a file from Supbase Storage.',
href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/read-storage/index.ts',
}
]
You can find a list of useful [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository.
@@ -0,0 +1,131 @@
---
id: migrating-and-upgrading-projects
title: 'Migrating and Upgrading Projects'
description: Upgrade your project to the latest version of Supabase.
sidebar_label: 'Migrating and upgrading'
---
Supabase ships fast and we endeavor to add all new features to existing projects wherever possible.
In some cases, access to new features require upgrading or migrating your Supabase project.
## Upgrade your project
When you pause and restore a project, the restored database includes the latest features. This method _does_ include downtime, so be aware that your project will be inaccessible for a short period of time.
1. On the [General Settings](https://app.supabase.com/project/_/settings/general) page in the Dashboard, click **Pause project**. You will be redirected to the home screen as your project is pausing. This process can take several minutes.
1. After your project is paused, click **Restore project**. The restoration can take several minutes depending on how much data your database has. You will receive an email once the restoration is complete.
## Migrate your project
Migrating projects can be achieved using standard PostgreSQL tooling. This is particularly useful for older projects (e.g. to use a newer Postgres version).
### Before you begin
- Install [Postgres](https://www.postgresql.org/download/) so you can run `psql` and `pg_dump`.
- Create a new [Supabase project](https://app.supabase.com).
- Store the old project's database URL as `$OLD_DB_URL` and the new project's as `$NEW_DB_URL`.
### Migrate the database
1. Enable [Database Webhooks](https://app.supabase.com/project/_/database/hooks) in your new project if you enabled them in your old project.
2. In your new project, enable all extensions that were enabled in your old project.
3. Run the following command from your terminal:
```sh
set -euo pipefail
pg_dump \
--clean \
--if-exists \
--quote-all-identifiers \
--exclude-table-data 'storage.objects' \
--exclude-schema 'extensions|graphql|graphql_public|net|pgbouncer|pgsodium|pgsodium_masks|realtime|supabase_functions|pg_toast|pg_catalog|information_schema' \
--schema '*' \
--dbname "$OLD_DB_URL" \
| sed 's/^DROP SCHEMA IF EXISTS "auth";$/-- DROP SCHEMA IF EXISTS "auth";/' \
| sed 's/^DROP SCHEMA IF EXISTS "storage";$/-- DROP SCHEMA IF EXISTS "storage";/' \
| sed 's/^CREATE SCHEMA "auth";$/-- CREATE SCHEMA "auth";/' \
| sed 's/^CREATE SCHEMA "storage";$/-- CREATE SCHEMA "storage";/' \
| sed 's/^ALTER DEFAULT PRIVILEGES FOR ROLE "supabase_admin"/-- ALTER DEFAULT PRIVILEGES FOR ROLE "supabase_admin"/' \
> dump.sql
psql \
--single-transaction \
--variable ON_ERROR_STOP=1 \
--file dump.sql \
--dbname "$NEW_DB_URL"
```
### Enable publication on tables
Replication for Realtime is disabled for all tables in your new project. On the [Replication](https://app.supabase.com/project/_/database/replication) page in the Dashboard, select your new project and enable replication for tables that were enabled in your old project.
### Migrate Storage objects
The new project has the old project's Storage buckets, but the Storage objects need to be migrated manually. Use this script to move storage objects from one project to another. If you have more than 10k objects, we can move the objects for you. Just contact us at [support@supabase.com](mailto:support@supabase.com).
```js
// npm install @supabase/supabase-js@1
const { createClient } = require('@supabase/supabase-js')
const OLD_PROJECT_URL = 'https://xxx.supabase.co'
const OLD_PROJECT_SERVICE_KEY = 'old-project-service-key-xxx'
const NEW_PROJECT_URL = 'https://yyy.supabase.co'
const NEW_PROJECT_SERVICE_KEY = 'new-project-service-key-yyy'
;(async () => {
const oldSupabaseRestClient = createClient(
OLD_PROJECT_URL,
OLD_PROJECT_SERVICE_KEY,
{
schema: 'storage',
}
)
const oldSupabaseClient = createClient(
OLD_PROJECT_URL,
OLD_PROJECT_SERVICE_KEY
)
const newSupabaseClient = createClient(
NEW_PROJECT_URL,
NEW_PROJECT_SERVICE_KEY
)
// make sure you update max_rows in postgrest settings if you have a lot of objects
// or paginate here
const { data: oldObjects, error } = await oldSupabaseRestClient
.from('objects')
.select()
if (error) {
console.log('error getting objects from old bucket')
throw error
}
for (const objectData of oldObjects) {
console.log(`moving ${objectData.id}`)
try {
const { data, error: downloadObjectError } =
await oldSupabaseClient.storage
.from(objectData.bucket_id)
.download(objectData.name)
if (downloadObjectError) {
throw downloadObjectError
}
const { _, error: uploadObjectError } = await newSupabaseClient.storage
.from(objectData.bucket_id)
.upload(objectData.name, data, {
upsert: true,
contentType: objectData.metadata.mimetype,
cacheControl: objectData.metadata.cacheControl,
})
if (uploadObjectError) {
throw uploadObjectError
}
} catch (err) {
console.log('error moving ', objectData)
console.log(err)
}
}
})()
```
@@ -14,6 +14,17 @@ import ProjectSetup from './_partials/project_setup.mdx'
![Supabase User Management example](/img/user-management-demo.png)
### Video Guide
<div class="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/0Fs96oZ4se0"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management).
+1 -1
View File
@@ -34,7 +34,7 @@ Reference documentation for the official Supabase client libraries, APIs, and to
</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 organizations and projects."/>
<ButtonCard icon={useBaseUrl("/img/icons/api-icon.svg")} class="card" to={useBaseUrl("/reference/api")} style={{ height: '100%' }} title="Management API" description="Manage your Supabase projects programmatically."/>
</div>
{/* */}
+12 -9
View File
@@ -109,12 +109,6 @@ const sidebars = {
},
],
},
{
type: 'category',
label: 'APIs',
collapsed: true,
items: ['guides/api', 'guides/api/generating-types'],
},
{
type: 'category',
label: 'Database',
@@ -124,20 +118,28 @@ const sidebars = {
'guides/database/connecting-to-postgres',
'guides/database/tables',
'guides/database/functions',
'guides/database/webhooks',
'guides/database/full-text-search',
'guides/database/migrating-between-projects',
// 'guides/database/json',
// 'guides/database/arrays',
// 'guides/database/sql-to-api',
{
type: 'category',
label: 'Data APIs',
collapsed: true,
items: ['guides/api', 'guides/api/generating-types'],
},
{
type: 'category',
label: 'Extensions',
collapsed: true,
items: [
'guides/database/extensions',
'guides/database/extensions/plv8',
'guides/database/extensions/http',
'guides/database/extensions/pgcron',
'guides/database/extensions/pgnet',
'guides/database/extensions/pgtap',
'guides/database/extensions/plv8',
'guides/database/extensions/uuid-ossp',
],
},
@@ -191,6 +193,7 @@ const sidebars = {
'guides/platform/disk-usage',
'guides/platform/logs',
'guides/platform/metrics',
'guides/platform/migrating-and-upgrading-projects',
'guides/platform/performance',
'guides/platform/permissions',
'going-into-prod',
@@ -285,7 +288,7 @@ const sidebars = {
href: '/reference/dart',
},
{ type: 'link', label: 'Supabase CLI', href: '/reference/cli' },
{ type: 'link', label: 'Supabase API', href: '/reference/api' },
{ type: 'link', label: 'Management API', href: '/reference/api' },
],
},
// TODO: add back in with typedocs
+21
View File
@@ -0,0 +1,21 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*/generated
+37
View File
@@ -0,0 +1,37 @@
---
slug: /
sidebar_position: 1
sidebar_label: Supabase API
---
# Supabase API
The Supabase API allows you to manage your projects programmatically.
## Status
The Supabase API is in `beta`. It is usable in it's current state, but it's likely that there will be breaking changes.
## Authentication
All API requests require a Supabase Personal token to be included in the Authorization header: `Authorization Bearer <supabase_personal_token`.
To generate or manage your API token, visit your [account](https://app.supabase.com/account/tokens) page.
Your API tokens carry the same privileges as your user account, so be sure to keep it secret.
```bash
$ curl https://api.supabase.com/v1/projects \
-H "Authorization: Bearer sbp_bdd0••••••••••••••••••••••••••••••••4f23"
```
All API requests must be authenticated and made over HTTPS.
## Rate limits
The API is currently subject to our fair-use policy. In the future, are likely to introduce rate limits.
All resources created via the API are subject to the pricing detailed on our [Pricing](https://supabase.com/pricing) pages.
## Additional links
- [OpenAPI Docs](https://api.supabase.com/api/v1)
- [OpenAPI Spec](https://api.supabase.com/api/v1-json)
- Reporting bugs and issues: [github.com/supabase/supabase](https://github.com/supabase/supabase)
+12
View File
@@ -0,0 +1,12 @@
---
id: release-notes
---
# Release Notes
## v1.0.0 {#1.0.0}
Adds the following routes:
- `/v1/organizations`: Manage Supabase organizations
- `/v1/projects`: Manage Supabase projects
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
[]
+29
View File
@@ -0,0 +1,29 @@
---
id: intro
slug: /
sidebar_position: 1
sidebar_label: Supabase CLI
hide_table_of_contents: true
---
# Supabase CLI
The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform.
The CLI is still under development, but it contains all the functionality for working with your Supabase projects and the Supabase Platform.
- Run Supabase locally: [`supabase start`](https://supabase.com/docs/reference/cli/usage#supabase-start)
- Manage database migrations: [`supabase migration`](https://supabase.com/docs/reference/cli/usage#supabase-migration)
- CI/CD for releasing to production: [`supabase db push`](https://supabase.com/docs/reference/cli/usage#supabase-db-push)
- Manage your Supabase projects: [`supabase projects`](https://supabase.com/docs/reference/cli/usage#supabase-projects)
- Generate types directly from your database schema: [`supabase gen types`](https://supabase.com/docs/reference/cli/usage#supabase-gen)
- A [community-supported GitHub Action](https://github.com/lyqht/generate-supabase-db-types-github-action) to generate TypeScript types
- Shell autocomplete: [`supabase completion`](https://supabase.com/docs/reference/cli/usage#supabase-completion)
- A [community-supported Fig autocomplete spec](https://fig.io/manual/supabase) for macOS terminal
## Additional Links
- [Install the Supabase CLI](/docs/guides/cli)
- [Source code](https://github.com/supabase/cli)
- [Known bugs and issues](https://github.com/supabase/cli/issues)
- [Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
- [The CLI team announcing CLI V1 and Admin API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28)
+7
View File
@@ -0,0 +1,7 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases page](https://github.com/supabase/cli/releases).
Whitespace-only changes.
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
[]
+35
View File
@@ -0,0 +1,35 @@
---
id: config
slug: /config
title: Configuration
toc_max_heading_level: 3
---
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
A `config.toml` file is generated after running `supabase init`.
This file is located in the `supabase` folder under `supabase/config.toml`.
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
## General {#general}
### `project_id` {#project_id}
A string used to distinguish different Supabase projects on the same host. Defaults to the working directory name when running `supabase init`.
<ul>
<li>Required: <code>true</code></li>
<li>Default: <code>None</code></li>
</ul>
<br />
+22
View File
@@ -0,0 +1,22 @@
---
slug: /
sidebar_position: 1
sidebar_label: Auth Server
---
# Supabase Auth Server
The Supabase Auth Server (GoTrue) is a JSON Web Token (JWT)-based API for managing users and issuing access tokens.
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
- [JavaScript](https://github.com/supabase/gotrue-js)
- [Dart](https://github.com/supabase/gotrue-dart)
## Additional Links
- [Source Code](https://github.com/supabase/gotrue)
- [Known bugs and issues](https://github.com/supabase/gotrue/issues)
- [Auth Guides](https://supabase.com/docs/guides/auth)
+7
View File
@@ -0,0 +1,7 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases](https://github.com/supabase/gotrue/releases) page.
+18
View File
@@ -0,0 +1,18 @@
---
id: usage
slug: /usage
title: Usage
toc_max_heading_level: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
Documentation of the gotrue API.
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
Whitespace-only changes.
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
[]
+28
View File
@@ -0,0 +1,28 @@
---
slug: /
sidebar_position: 1
sidebar_label: Storage Server
---
# Supabase Storage Server
An S3 compatible object storage service that integrates with Postgres.
- Uses Postgres as it's datastore for storing metadata
- Authorization rules are written as Postgres Row Level Security policies
- Integrates with S3 as the storage backend (with more in the pipeline!)
- Extremely lightweight and performant
Read [this post](https://supabase.com/blog/supabase-storage) on why we decided to build a new object storage service.
## Client libraries
- [JavaScript](https://github.com/supabase/storage-js)
- [Dart](https://github.com/supabase/storage-dart)
## Additional Links
- [Source Code](https://github.com/supabase/storage-api)
- [Known bugs and issues](https://github.com/supabase/storage-js/issues)
- [Storage Guides](https://supabase.com/docs/guides/storage)
- [OpenAPI Docs](https://supabase.github.io/storage-api/)
@@ -0,0 +1,7 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases](https://github.com/supabase/storage-api/releases) page.
Whitespace-only changes.
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
[]
@@ -0,0 +1,43 @@
---
id: initializing
title: 'Initializing'
slug: initializing
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Flutter
For `supabase-flutter`, you will be using the static `initialize()` method on `Supabase` class.
### Flutter `initialize()`
```dart title="main.dart"
Future<void> main() async {
await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key');
runApp(MyApp());
}
```
### Access `SupabaseClient` instance
Once you initialize Supabase in your `main()` method, you can access the `SupabaseClient` instance from anywhere in your app.
```dart
final supabase = Supabase.instance.client;
```
## Other Dart Projects
You can initialize a new Supabase client using the `SupabaseClient()` 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.
### Dart `SupabaseClient()`
```dart
final supabase = SupabaseClient('https://xyzcompany.supabase.co', 'public-anon-key');
```
@@ -0,0 +1,24 @@
---
id: installing
title: 'Installing'
slug: installing
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Flutter
For Flutter project, you can use [supabase_flutter](https://pub.dev/packages/supabase_flutter) package.
```bash
flutter pub add supabase_flutter
```
## Other Dart projects
For non-Flutter projects using Dart, such as server-side Dart or Angular-Dart, you can use the [supabase](https://pub.dev/packages/supabase) package.
```bash
dart pub add supabase
```
+27
View File
@@ -0,0 +1,27 @@
---
id: intro
slug: /
sidebar_label: Supabase Flutter Library
---
# Supabase Flutter Library
This reference documents every object and method available in Supabase's isomorphic Flutter library, [`supabase-flutter`](https://pub.dev/packages/supabase_flutter).
You can use the `supabase-flutter` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## For non-Flutter projects
We also have [supabase-dart](https://github.com/supabase-community/supabase-dart) for non-Flutter Dart projects, such as server-side Dart or Angular-Dart.
supabase-dart shares most of the APIs with supabase-flutter without being dependent on Flutter so that you can use Supabase anywhere you can run Dart!
## Additional Links
- Source Code: [github.com/supabase/supabase-flutter](https://github.com/supabase/supabase-flutter)
- [Known bugs and issues](https://github.com/supabase/supabase-flutter/issues)
@@ -0,0 +1,27 @@
---
id: intro
slug: /
sidebar_label: Supabase Dart Library
---
# Supabase Dart Library
:::caution
You're viewing the docs for an older version of the `supabase-flutter` library.
:::
This reference documents every object and method available in Supabase's isomorphic Dart library, `supabase-dart`.
You can use the `supabase-dart` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## Additional Links
- Source Code: [github.com/supabase/supabase-dart](https://github.com/supabase/supabase-dart)
- [Known bugs and issues](https://github.com/supabase/supabase-dart/issues)
@@ -0,0 +1,120 @@
{
"sidebar": [
{
"type": "category",
"label": "Getting Started",
"items": ["intro", "generated/installing", "generated/initializing"],
"collapsed": true
},
{
"type": "category",
"label": "Auth",
"items": [
"generated/auth-signup",
"generated/auth-signin",
"generated/auth-signinwithprovider",
"generated/auth-signout",
"generated/auth-session",
"generated/auth-user",
"generated/auth-update",
"generated/auth-onauthstatechange",
"generated/reset-password-email"
],
"collapsed": true
},
{
"type": "category",
"label": "Functions",
"items": ["generated/invoke"],
"collapsed": true
},
{
"type": "category",
"label": "Database",
"items": [
"generated/select",
"generated/insert",
"generated/update",
"generated/upsert",
"generated/delete",
"generated/rpc"
],
"collapsed": true
},
{
"type": "category",
"label": "Realtime",
"items": [
"generated/subscribe",
"generated/removesubscription",
"generated/getsubscriptions",
"generated/stream"
],
"collapsed": true
},
{
"type": "category",
"label": "Storage",
"items": [
"generated/storage-createbucket",
"generated/storage-getbucket",
"generated/storage-listbuckets",
"generated/storage-updatebucket",
"generated/storage-deletebucket",
"generated/storage-emptybucket",
"generated/storage-from-upload",
"generated/storage-from-download",
"generated/storage-from-list",
"generated/storage-from-update",
"generated/storage-from-move",
"generated/storage-from-remove",
"generated/storage-from-createsignedurl",
"generated/storage-from-getpublicurl"
],
"collapsed": true
},
{
"type": "category",
"label": "Modifiers",
"items": [
"generated/using-modifiers",
"generated/limit",
"generated/order",
"generated/range",
"generated/single"
],
"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
}
]
}
@@ -0,0 +1 @@
["v0"]
@@ -1,42 +1,37 @@
---
id: installing
title: "Installing"
title: 'Installing'
slug: installing
custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
---
import Tabs from '@theme/Tabs';
import TabsPanel from '@theme/TabsPanel';
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
All JavaScript libraries are built directly by the Supabase team.
All JavaScript libraries are built directly by the Supabase team.
Other languages are built by the community and supported by Supabase.
## JavaScript
Via NPM
```bash
npm install @supabase/supabase-js
```
Via Yarn
```bash
yarn add @supabase/supabase-js
```
Find the source code on [GitHub](https://github.com/supabase/supabase-js).
Find the source code on [GitHub](https://github.com/supabase/supabase-js).
Or via CDN
```js
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
//or
<script src="https://unpkg.com/@supabase/supabase-js@2"></script>
```
## Python
```bash
pip install supabase-py
```
Find the source code on [GitHub](https://github.com/supabase/supabase-py).
+25
View File
@@ -0,0 +1,25 @@
---
slug: /
sidebar_position: 1
sidebar_label: Supabase JavaScript Library
hide_table_of_contents: true
---
# Supabase JavaScript Library
This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`.
You can use the `supabase-js` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## Additional Links
- Source Code: [github.com/supabase/supabase-js](https://github.com/supabase/supabase-js)
- TypeDoc: [supabase.github.io/supabase-js](https://supabase.github.io/supabase-js/v2/)
- NPM: [npmjs.com/package/@supabase/supabase-js](https://www.npmjs.com/package/@supabase/supabase-js)
- [Known bugs and issues](https://github.com/supabase/supabase-js/issues)
@@ -0,0 +1,211 @@
---
id: release-notes
---
# Release Notes
Supabase.js v2 release notes.
## 2.0.0
Install the latest with `npm install @supabase/supabase-js`.
### Explicit constructor options
All client specific options within the constructor are keyed to the library: [PR](https://github.com/supabase/supabase-js/pull/458):
```jsx
const supabase = createClient(apiURL, apiKey, {
db: {
schema: 'public',
},
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
realtime: {
channels,
endpoint,
},
global: {
fetch: customFetch,
headers: DEFAULT_HEADERS,
},
})
```
### Typescript support
The libraries now support typescript.
```ts
// v2 - definitions are injected in `createClient()`
import type { Database } from './DatabaseDefinitions'
const supabase = createClient<Database>(SUPABASE_URL, ANON_KEY)
const { data } = await supabase.from('messages').select().match({ id: 1 })
// v1 -- previously definitions were injected in the `from()` method
supabase.from<Definitions['Message']>('messages').select('*')
```
Types can be generated via the CLI:
```bash
supabase start
supabase gen types typescript --local > DatabaseDefinitions.ts
```
### Data operations return minimal
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default: [PR](https://github.com/supabase/postgrest-js/pull/276).
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end, e.g.:
```sql
const { data, error } = await supabase
.from('my_table')
.delete()
.eq('id', 1)
.select()
```
### New ordering defaults
`.order()` now defaults to Postgres’s default: [PR](https://github.com/supabase/postgrest-js/pull/283).
Previously `nullsFirst` defaults to `false` , meaning `null`s are ordered last. This is bad for performance if e.g. the column uses an index with `NULLS FIRST` (which is the default direction for indexes).
### Cookies and localstorage namespace
Storage key name in the Auth library has changed to include project reference which means that existing websites that had their JWT expiry set to a longer time could find their users logged out with this upgrade.
```jsx
const defaultStorageKey = `sb-${new URL(this.authUrl).hostname.split('.')[0]}-auth-token`
```
### New Auth Types
Typescript typings have been reworked. `Session` interface now guarantees that it will always have an `access_token`, `refresh_token` and `user`
```jsx
interface Session {
provider_token?: string | null
access_token: string
expires_in?: number
expires_at?: number
refresh_token: string
token_type: string
user: User
}
```
### New Auth methods
We're removing the `signIn()` method in favor of more explicit function signatures:
`signInWithPassword()`, `signInWithPasswordless()`, and `signInWithOtp()`.
```ts
// v2
const { data } = await supabase.auth.signInWithPassword({
email: 'hello@example',
password: 'pass',
})
// v1
const { data } = await supabase.auth.signIn({
email: 'hello@example',
password: 'pass',
})
```
### New Realtime methods
There is a new `channel()` method in the Realtime library, which will be used for our Multiplayer updates.
```ts
supabaseClient
.channel('any_string_you_want')
.on('presence', { event: 'track' }, (payload) => {
console.log(payload)
})
.subscribe()
supabaseClient
.channel('any_string_you_want')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'movies',
},
(payload) => {
console.log(payload)
}
)
.subscribe()
```
We will deprecate the `.from().on().subscribe()` method previosuly used for listening to postgres changes.
### Deprecated setAuth()
Deprecated and removed `setAuth()` . To set a custom `access_token` jwt instead, pass the custom header into the `createClient()` method provided: ([PR](https://github.com/supabase/gotrue-js/pull/340))
### All changes
- `supabase-js`
- `shouldThrowOnError` has been removed until all the client libraries support this option ([PR](https://github.com/supabase/supabase-js/pull/490)).
- `postgrest-js`
- TypeScript typings have been reworked [PR](https://github.com/supabase/postgrest-js/pull/279)
- Use `undefined` instead of `null` for function params, types, etc. (https://github.com/supabase/postgrest-js/pull/278)
- Some features are now obsolete: (https://github.com/supabase/postgrest-js/pull/275)
- filter shorthands (e.g. `cs` vs. `contains`)
- `body` in response (vs. `data`)
- `upsert`ing through the `.insert()` method
- `auth` method on `PostgrestClient`
- client-level `throwOnError`
- `gotrue-js`
- `supabase-js` client allows passing a `storageKey` param which will allow the user to set the key used in local storage for storing the session. By default, this will be namespace-d with the supabase project ref. ([PR](https://github.com/supabase/supabase-js/pull/460))
- `signIn` method is now split into `signInWithPassword` , `signInWithPasswordless` , `signInWithOAuth` ([PR](https://github.com/supabase/gotrue-js/pull/304))
- Deprecated and removed `session()` , `user()` in favour of using `getSession()` instead. `getSession()` will always return a valid session if a user is already logged in, meaning no more random logouts. ([PR](https://github.com/supabase/gotrue-js/pull/299))
- Deprecated and removed setting for `multitab` support because `getSession()` and gotrue’s reuse interval setting takes care of session management across multiple tabs ([PR](https://github.com/supabase/gotrue-js/pull/366))
- No more throwing of random errors, gotrue-js v2 always returns a custom error type: ([PR](https://github.com/supabase/gotrue-js/pull/341))
- `AuthSessionMissingError`
- Indicates that a session is expected but missing
- `AuthNoCookieError`
- Indicates that a cookie is expected but missing
- `AuthInvalidCredentialsError`
- Indicates that the incorrect credentials were passed
- Renamed the `api` namespace to `admin` , the `admin` namespace will only contain methods that should only be used in a trusted server-side environment with the service role key
- Moved `resetPasswordForEmail` , `getUser` and `updateUser` to the `GoTrueClient` which means they will be accessible from the `supabase.auth` namespace in `supabase-js` instead of having to do `supabase.auth.api` to access them
- Removed `sendMobileOTP` , `sendMagicLinkEmail` in favor of `signInWithOtp`
- Removed `signInWithEmail`, `signInWithPhone` in favor of `signInWithPassword`
- Removed `signUpWithEmail` , `signUpWithPhone` in favor of `signUp`
- Replaced `update` with `updateUser`
- `storage-js`
- Return types are more strict. Functions types used to indicate that the data returned could be null even if there was no error. We now make use of union types which only mark the data as null if there is an error and vice versa. ([PR](https://github.com/supabase/storage-js/pull/60))
- The `upload` and `update` function returns the path of the object uploaded as the `path` parameter. Previously the returned value had the bucket name prepended to the path which made it harder to pass the value on to other storage-js methods since all methods take the bucket name and path separately. We also chose to call the returned value `path` instead of `Key` ([PR](https://github.com/supabase/storage-js/pull/75))
- `getPublicURL` only returns the public URL inside the data object. This keeps it consistent with our other methods of returning only within the data object. No error is returned since this method cannot does not throw an error ([PR](https://github.com/supabase/storage-js/pull/93))
- signed urls are returned as `signedUrl` instead of `signedURL` in both `createSignedUrl` and `createSignedUrls` ([PR](https://github.com/supabase/storage-js/pull/94))
- Encodes URLs returned by `createSignedUrl`, `createSignedUrls` and `getPublicUrl` ([PR](https://github.com/supabase/storage-js/pull/86))
- `createsignedUrl` used to return a url directly and and within the data object. This was inconsistent. Now we always return values only inside the data object across all methods. ([PR](https://www.notion.so/LW5-supabase-js-v2-7b0bfcdf571d4f20b9b7a9308883f24b))
- `createBucket` returns a data object instead of the name of the bucket directly. ([PR](https://github.com/supabase/storage-js/pull/89))
- Fixed types for metadata ([PR](https://github.com/supabase/storage-js/pull/90))
- Better error types make it easier to track down what went wrong quicker.
- `SupabaseStorageClient` is no longer exported. Use `StorageClient` instead. ([PR](https://github.com/supabase/storage-js/pull/92)).
- `realtime-js`
- `RealtimeSubscription` class no longer exists and replaced by `RealtimeChannel`.
- `RealtimeClient`'s `disconnect` method now returns type of `void` . It used to return type of `Promise<{ error: Error | null; data: boolean }`.
- Removed `removeAllSubscriptions` and `removeSubscription` methods from `SupabaseClient` class.
- Removed `SupabaseRealtimeClient` class.
- Removed `SupabaseQueryBuilder` class.
- Removed `SupabaseEventTypes` type.
- Thinking about renaming this to something like `RealtimePostgresChangeEvents` and moving it to `realtime-js` v2.
- Removed `.from(’table’).on(’INSERT’, () ⇒ {}).subscribe()` in favor of new Realtime client API.
- `functions-js`
- supabase-js v1 only threw an error if the fetch call itself threw an error (network errors, etc) and not if the function returned HTTP errors like 400s or 500s. We have changed this behaviour to return an error if your function throws an error.
- We have introduced new error types to distinguish between different kinds of errors. A `FunctionsHttpError` error is returned if your function throws an error, `FunctionsRelayError` if the Supabase Relay has an error processing your function and `FunctionsFetchError` if there is a network error in calling your function.
- The correct content-type headers are automatically attached when sending the request if you don’t pass in a `Content-Type` header and pass in an argument to your function. We automatically attach the content type for `Blob`, `ArrayBuffer`, `File`, `FormData` ,`String` . If it doesn’t match any of these we assume the payload is `json` , we serialise the payload as JSON and attach the content type as `application/json`.
- `responseType` does not need to be explicitly passed in. We parse the response based on the `Content-Type` response header sent by the function. We support parsing the responses as `text`, `json`, `blob`, `form-data` and are parsed as `text` by default.
@@ -0,0 +1,461 @@
---
id: upgrade-guide
title: Upgrade to supabase-js v2
description: 'Learn how to upgrade to supabase-js v2.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
supabase-js v2 focuses on "quality-of-life" improvements for developers and addresses some of the largest pain points in v1. v2 includes type support, a rebuilt Auth library with async methods, improved errors, and more.
No new features will be added to supabase-js v1 , but we'll continuing merging security fixes to v1, with maintenance patches for the next 3 months.
## Upgrade the client library
```sh
npm install @supabase/supabase-js@2
```
_Optionally_ if you are using custom configuration with `createClient` then follow below:
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts title="src/supabaseClient.ts"
const supabaseClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
schema: 'custom',
persistSession: false,
})
```
</TabItem>
<TabItem value="2.x">
```ts title="src/supabaseClient.ts"
const supabaseClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
db: {
schema: 'custom',
},
auth: {
persistSession: true,
},
})
```
</TabItem>
</Tabs>
Read more about the [constructor options](/docs/reference/javascript/release-notes#explicit-constructor-options).
### Auth methods
The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).
#### Sign in with email and password
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = await supabase.auth.signIn({ email, password })
```
</TabItem>
<TabItem value="2.x">
```ts
const {
data: { user },
error,
} = await supabase.auth.signInWithPassword({ email, password })
```
</TabItem>
</Tabs>
#### Sign in with magic link
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ email })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithOtp({ email })
```
</TabItem>
</Tabs>
#### Sign in with a third-party provider
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ provider })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithOAuth({ provider })
```
</TabItem>
</Tabs>
#### Sign in with phone
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ phone, password })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithPassword({ phone, password })
```
</TabItem>
</Tabs>
#### Sign in with phone using OTP
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.api.sendMobileOTP(phone)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.signInWithOtp({ phone })
// After receiving a SMS with a OTP.
const { data, error } = await supabase.auth.verifyOtp({ phone, token })
```
</TabItem>
</Tabs>
#### Reset password for email
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.api.resetPasswordForEmail(email)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.resetPasswordForEmail(email)
```
</TabItem>
</Tabs>
#### Get the user's current session
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const session = supabase.auth.session()
```
</TabItem>
<TabItem value="2.x">
```ts
const {
data: { session },
} = await supabase.auth.getSession()
```
</TabItem>
</Tabs>
#### Get the logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const user = supabase.auth.user()
```
</TabItem>
<TabItem value="2.x">
```ts
const {
data: { session },
} = await supabase.auth.getSession()
const { user } = session
```
</TabItem>
</Tabs>
#### Update user data for a logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = await supabase.auth.update({ attributes })
```
</TabItem>
<TabItem value="2.x">
```ts
const {
data: { user },
error,
} = await supabase.auth.updateUser({ attributes })
```
</TabItem>
</Tabs>
#### Use a custom `access_token` JWT with Supabase
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = supabase.auth.setAuth(access_token)
```
</TabItem>
<TabItem value="2.x">
```ts
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
global: {
headers: {
Authorization: `Bearer ${access_token}`,
},
},
})
```
</TabItem>
</Tabs>
### Data methods
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default: [PR](https://github.com/supabase/postgrest-js/pull/276).
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end.
#### Insert and return data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.insert({ new_data })
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.insert({ new_data }).select()
```
</TabItem>
</Tabs>
#### Update and return data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.update({ new_data }).eq('id', id)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.update({ new_data }).eq('id', id).select()
```
</TabItem>
</Tabs>
### Realtime methods
#### Subscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const userListener = supabase
.from('users')
.on('*', (payload) => handleAllEventsPayload(payload.new))
.subscribe()
```
</TabItem>
<TabItem value="2.x">
```ts
const userListener = supabase.channel('public:user')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'user' }
(payload) => handleAllEventsPayload()
)
.subscribe()
```
</TabItem>
</Tabs>
#### Unsubscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
userListener.unsubscribe()
```
</TabItem>
<TabItem value="2.x">
```ts
supabase.removeChannel('public:users')
```
</TabItem>
</Tabs>
@@ -0,0 +1,81 @@
---
id: typescript-support
---
# Typescript Support
`supabase-js` supports Typescript.
## Generating types
You can use our CLI to generate types:
```bash
supabase start
supabase gen types typescript --local > lib/database.types.ts
```
These types are generated directly from your database. Given a table `public.movies`, the definition will provide the following data:
```ts
interface Database {
public: {
Tables: {
movies: {
Row: {} // The data expected to be returned from a "select" statement.
Insert: {} // The data expected passed to an "insert" statement.
Update: {} // The data expected passed to an "update" statement.
}
}
}
}
```
There is a difference between `selects`, `inserts`, and `updates`, because often you will set default values in your database for specific columns.
With default values you do not need to send any data over the network, even if that column is a "required" field. Our type system is granular
enough to handle these situations.
## Injecting type definitions
You can enrich the supabase client with the types you generated with Supabase.
```ts
import { createClient } from '@supabase/supabase-js'
import { Database } from 'lib/database.types'
const supabase = createClient<Database>(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY)
```
## Type hints
`supabase-js` always returns a `data` object (for success), and an `error` response (for unsuccessful requests).
This provides a simple interface to get the relevant types returned from any function:
```ts
export async function getMovies() {
return await supabase.from('movies').select(`id, title`)
}
type MoviesResponse = Awaited<ReturnType<typeof getMovies>>
export type MoviesResponseSuccess = MoviesResponse['data']
export type MoviesResponseError = MoviesResponse['error']
```
## Nested tables
For advanced queries such as nested tables, you may want to construct your own types.
```ts
import supabase from '~/lib/supabase'
import type { Database } from '~/lib/database.types'
async function getMovies() {
return await supabase.from('movies').select('id, title, actors(*)')
}
type Actors = Database['public']['Tables']['actors']['Row']
type MoviesResponse = Awaited<ReturnType<typeof getMovies>>
type MoviesResponseSuccess = MoviesResponse['data'] & {
actors: Actors[]
}
```
@@ -0,0 +1,42 @@
---
id: generating-types
title: 'Generating Types'
slug: generating-types
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Supabase will soon release native type generators that dump your database types for various languages. For now, we support TypeScript [through third-party tools](/docs/guides/api/generating-types).
## Usage with TypeScript
`supabase-js` ships with type definitions for usage with TypeScript and for convenient IntelliSense auto-complete and documentation in your editor.
When using TypeScript, you can pass the type of database row as a type parameter to the `from` method to get better auto-completion support down the chain.
If you don't provide a type for the row you need to explicitly pass `from<any>('tableName')`.
```ts
type Message = {
id: number
inserted_at: string
message: string
user_id: string
channel_id: number
author: { username: string }
}
const response = await supabase
.from<Message>('messages') // Message maps to the type of the row in your database.
.select('*, author:user_id(username)')
.match({ channel_id: 2 }) // Your IDE will be able to help with auto-completion.
response.data // Response data will be of type Array<Message>.
// If you don't provide a type for the row you need to explicitly pass `from<any>('tableName')`.
const response = await supabase
.from<any>('messages')
.select('*, author:user_id(username)')
.match({ channel_id: 2 })
response.data // Response data will be of type Array<any>.
```
@@ -0,0 +1,11 @@
---
id: index
title: 'Supabase Client'
slug: supabase-client
custom_edit_url: ../../spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Supabase JavaScript.
@@ -1,24 +1,20 @@
---
id: initializing
title: "Initializing"
title: 'Initializing'
slug: initializing
custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs';
import TabsPanel from '@theme/TabsPanel';
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">
@@ -41,7 +37,6 @@ The unique Supabase URL which is supplied when you create a new project in your
</li>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
@@ -62,7 +57,6 @@ The unique Supabase Key which is supplied when you create a new project in your
</li>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
@@ -77,7 +71,7 @@ The unique Supabase Key which is supplied when you create a new project in your
</h4>
<div class="method-list-item-description">
No description provided.
No description provided.
</div>
@@ -85,55 +79,22 @@ No description provided.
</ul>
## Examples
### createClient()
<Tabs
defaultActiveId="js"
groupId="reference/supabase-js"
values={[{ label: 'JavaScript', value: 'js' }]}>
<TabsPanel id="js" label="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')
// Create a single supabase client for interacting with your database
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key'
)
```
</TabsPanel>
</Tabs>
### With additional parameters
<Tabs
defaultActiveId="js"
groupId="reference/supabase-js"
values={[{ label: 'JavaScript', value: 'js' }]}>
<TabsPanel id="js" label="js">
```js
import { createClient } from '@supabase/supabase-js'
@@ -142,70 +103,49 @@ const options = {
headers: { 'x-my-custom-header': 'my-app-name' },
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true
detectSessionInUrl: true,
}
const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key", options)
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key',
options
)
```
</TabsPanel>
</Tabs>
### API schemas
<Tabs
defaultActiveId="js"
groupId="reference/supabase-js"
values={[{ label: 'JavaScript', value: 'js' }]}>
<TabsPanel id="js" label="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'
})
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.
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.
</TabsPanel>
</Tabs>
### Custom `fetch` implementation
<Tabs
defaultActiveId="js"
groupId="reference/supabase-js"
values={[{ label: 'JavaScript', value: 'js' }]}>
<TabsPanel id="js" label="js">
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', {
fetch: fetch.bind(globalThis)
})
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.
`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).
</TabsPanel>
</Tabs>
@@ -0,0 +1,37 @@
---
id: installing
title: 'Installing'
slug: installing
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
All JavaScript libraries are built directly by the Supabase team.
Other languages are built by the community and supported by Supabase.
## JavaScript
Via NPM
```bash
npm install @supabase/supabase-js
```
Via Yarn
```bash
yarn add @supabase/supabase-js
```
Find the source code on [GitHub](https://github.com/supabase/supabase-js).
Or via CDN
```js
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@1"></script>
//or
<script src="https://unpkg.com/@supabase/supabase-js@1"></script>
```
@@ -0,0 +1,20 @@
---
id: intro
title: 'Supabase JavaScript Library'
slug: /
sidebar_label: Supabase JavaScript Library
---
:::caution
You're viewing the docs for an older version of the `supabase-js` library.
:::
This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`.
You can use the `supabase-js` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
Whitespace-only changes.
@@ -0,0 +1,138 @@
{
"sidebar": [
{
"type": "category",
"label": "Getting Started",
"items": ["intro", "installing", "initializing", "generating-types"],
"collapsed": false
},
{
"type": "category",
"label": "Auth",
"items": [
"generated/auth-signup",
"generated/auth-signin",
"generated/auth-signout",
"generated/auth-session",
"generated/auth-user",
"generated/auth-update",
"generated/auth-setauth",
"generated/auth-onauthstatechange",
"generated/auth-api-getuser",
"generated/auth-api-resetpasswordforemail"
],
"collapsed": true
},
{
"type": "category",
"label": "Auth (Server Only)",
"items": [
"generated/auth-api-listusers",
"generated/auth-api-createuser",
"generated/auth-api-deleteuser",
"generated/auth-api-generatelink",
"generated/auth-api-inviteuserbyemail",
"generated/auth-api-sendmobileotp",
"generated/auth-api-updateuserbyid"
],
"collapsed": true
},
{
"type": "category",
"label": "Functions",
"items": ["generated/invoke"],
"collapsed": true
},
{
"type": "category",
"label": "Database",
"items": [
"generated/select",
"generated/insert",
"generated/update",
"generated/upsert",
"generated/delete",
"generated/rpc"
],
"collapsed": true
},
{
"type": "category",
"label": "Realtime",
"items": [
"generated/subscribe",
"generated/removesubscription",
"generated/removeallsubscriptions",
"generated/getsubscriptions"
],
"collapsed": true
},
{
"type": "category",
"label": "Storage",
"items": [
"generated/storage-createbucket",
"generated/storage-getbucket",
"generated/storage-listbuckets",
"generated/storage-updatebucket",
"generated/storage-deletebucket",
"generated/storage-emptybucket",
"generated/storage-from-upload",
"generated/storage-from-download",
"generated/storage-from-list",
"generated/storage-from-update",
"generated/storage-from-move",
"generated/storage-from-copy",
"generated/storage-from-remove",
"generated/storage-from-createsignedurl",
"generated/storage-from-createsignedurls",
"generated/storage-from-getpublicurl"
],
"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
}
]
}
@@ -0,0 +1 @@
["v1"]
+1 -1
View File
@@ -1,5 +1,5 @@
import authProviders from '../data/authProviders'
import { Card } from '@supabase/ui'
import { Card } from 'ui'
import Link from 'next/link'
export default function AuthProviders() {
+35
View File
@@ -0,0 +1,35 @@
import React from 'react'
import Link from 'next/link'
export default function ButtonCard({
children = undefined,
icon = undefined,
title,
description = '',
to,
layout = 'vertical',
}) {
return (
<Link href={to}>
<a className={['button-card h-full pb-4 block', `button-card--${layout}`].join(' ')}>
{children ? (
children
) : (
<div
className={`button-card__inner p-4 gap-1 flex ${
layout === 'vertical' ? 'flex-col' : 'items-center'
}`}
>
{icon && typeof icon == 'string' ? (
<img className="m-0" src={icon} width={24} alt={title} />
) : (
icon
)}
<h3 className="mt-0">{title}</h3>
<p>{description}</p>
</div>
)}
</a>
</Link>
)
}
@@ -1,12 +1,13 @@
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
import monokaiCustomTheme from './CodeBlock.utils'
import { Button, IconCheck, IconCopy } from '@supabase/ui'
import { Button, IconCheck, IconCopy } from 'ui'
import CopyToClipboard from 'react-copy-to-clipboard'
import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'
import py from 'react-syntax-highlighter/dist/cjs/languages/hljs/python'
import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql'
import { useState } from 'react'
import { useTheme } from '../Providers'
interface Props {
lang: 'js' | 'sql' | 'py'
@@ -16,8 +17,10 @@ interface Props {
children?: string
size?: 'small' | 'medium' | 'large'
}
function CodeBlock(props: Props) {
const { isDarkMode } = useTheme()
const monokaiTheme = monokaiCustomTheme(isDarkMode)
const [copied, setCopied] = useState(false)
const handleCopy = () => {
@@ -42,26 +45,31 @@ function CodeBlock(props: Props) {
// const large = props.size === 'large' ? true : false
const large = false
// don't show line numbers if bash == lang
const showLineNumbers = lang !== 'bash'
return (
<div className="relative">
<SyntaxHighlighter
language={lang}
style={monokaiCustomTheme}
className={'code-block border-scale-600 rounded-lg border'}
style={monokaiTheme}
className={`code-block rounded-lg border p-4 ${!showLineNumbers && 'pl-6'}`}
customStyle={{
padding: 0,
fontSize: large ? 18 : 12,
lineHeight: large ? 1.2 : 1.2,
borderTop: '1px solid #393939',
background: '#181818',
lineHeight: large ? 1.4 : 1.2,
// borderTop: '1px solid #393939',
//background: isDarkMode ? 'bg-scale-700' : 'bg-scale-300',
//background: isDarkMode ? '#444' : '#F1F3F5',
// we really should support proper light mode, not just show dark in both modes
background: isDarkMode ? '#444' : '#F1F3F5',
}}
showLineNumbers={lang === 'cli' ? false : true}
showLineNumbers={showLineNumbers}
lineNumberContainerStyle={{
paddingTop: '128px',
}}
lineNumberStyle={{
minWidth: '44px',
background: '#1e1e1e',
background: isDarkMode ? '#444' : '#F1F3F5',
paddingLeft: '4px',
paddingRight: '4px',
marginRight: '12px',
@@ -75,7 +83,7 @@ function CodeBlock(props: Props) {
{props.children?.trimEnd()}
</SyntaxHighlighter>
{!props.hideCopy && props.children ? (
<div className="dark absolute right-2 top-2">
<div className={`${isDarkMode ?? 'dark'} absolute right-2 top-2`}>
<CopyToClipboard text={props.children}>
<Button
type="default"
@@ -1,116 +1,117 @@
const monokaiCustomTheme = {
hljs: {
display: 'block',
overflowX: 'auto',
padding: '0.5em',
background: '#272822',
color: '#ddd',
},
'hljs-tag': {
color: '#569cd6',
},
'hljs-keyword': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-selector-tag': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-literal': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-strong': {
color: '#569cd6',
},
'hljs-name': {
color: '#569cd6',
},
'hljs-code': {
color: '#66d9ef',
},
'hljs-class .hljs-title': {
color: 'gray',
},
'hljs-attribute': {
color: '#bf79db',
},
'hljs-symbol': {
color: '#bf79db',
},
'hljs-regexp': {
color: '#bf79db',
},
'hljs-link': {
color: '#bf79db',
},
'hljs-string': {
color: '#3ECF8E',
},
'hljs-bullet': {
color: '#3ECF8E',
},
'hljs-subst': {
color: '#3ECF8E',
},
'hljs-title': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-section': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-emphasis': {
color: '#3ECF8E',
},
'hljs-type': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-built_in': {
color: '#3ECF8E',
},
'hljs-builtin-name': {
color: '#3ECF8E',
},
'hljs-selector-attr': {
color: '#3ECF8E',
},
'hljs-selector-pseudo': {
color: '#3ECF8E',
},
'hljs-addition': {
color: '#3ECF8E',
},
'hljs-variable': {
color: '#3ECF8E',
},
'hljs-template-tag': {
color: '#3ECF8E',
},
'hljs-template-variable': {
color: '#3ECF8E',
},
'hljs-comment': {
color: '#75715e',
},
'hljs-quote': {
color: '#75715e',
},
'hljs-deletion': {
color: '#75715e',
},
'hljs-meta': {
color: '#75715e',
},
'hljs-doctag': {
fontWeight: 'normal',
},
'hljs-selector-id': {
fontWeight: 'normal',
},
const monokaiCustomTheme = (isDarkMode) => {
return {
hljs: {
display: 'block',
overflowX: 'auto',
background: '#272822',
color: '#ddd',
},
'hljs-tag': {
color: '#569cd6',
},
'hljs-keyword': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-selector-tag': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-literal': {
color: '#569cd6',
fontWeight: 'normal',
},
'hljs-strong': {
color: '#569cd6',
},
'hljs-name': {
color: '#569cd6',
},
'hljs-code': {
color: '#66d9ef',
},
'hljs-class .hljs-title': {
color: 'gray',
},
'hljs-attribute': {
color: '#bf79db',
},
'hljs-symbol': {
color: '#bf79db',
},
'hljs-regexp': {
color: '#bf79db',
},
'hljs-link': {
color: '#bf79db',
},
'hljs-string': {
color: '#3ECF8E',
},
'hljs-bullet': {
color: '#3ECF8E',
},
'hljs-subst': {
color: '#3ECF8E',
},
'hljs-title': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-section': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-emphasis': {
color: '#3ECF8E',
},
'hljs-type': {
color: '#3ECF8E',
fontWeight: 'normal',
},
'hljs-built_in': {
color: '#3ECF8E',
},
'hljs-builtin-name': {
color: '#3ECF8E',
},
'hljs-selector-attr': {
color: '#3ECF8E',
},
'hljs-selector-pseudo': {
color: '#3ECF8E',
},
'hljs-addition': {
color: '#3ECF8E',
},
'hljs-variable': {
color: '#3ECF8E',
},
'hljs-template-tag': {
color: '#3ECF8E',
},
'hljs-template-variable': {
color: '#3ECF8E',
},
'hljs-comment': {
color: isDarkMode ? '#999' : '#888',
},
'hljs-quote': {
color: '#75715e',
},
'hljs-deletion': {
color: '#75715e',
},
'hljs-meta': {
color: '#75715e',
},
'hljs-doctag': {
fontWeight: 'normal',
},
'hljs-selector-id': {
fontWeight: 'normal',
},
}
}
export default monokaiCustomTheme
@@ -0,0 +1,17 @@
export const getAnchor = (text: any): string | undefined => {
if (typeof text !== 'string') {
return undefined
} else {
const [anchor] = text.match(/{#[a-z-]*}/g) || []
return anchor !== undefined ? anchor.slice(2, anchor.length - 1) : undefined
}
}
export const removeAnchor = (text: any) => {
if (typeof text !== 'string') {
return text
} else {
if (text.indexOf('{#') > 0) return text.slice(0, text.indexOf('{#'))
else return text
}
}
@@ -0,0 +1,17 @@
import { getAnchor, removeAnchor } from './CustomMDX.utils'
const H3 = ({ children }) => {
const anchor = getAnchor(children)
const link = `#${anchor}`
return (
<h3 id={anchor} className="group">
{removeAnchor(children)}
{anchor && (
<a href={link} className="opacity-0 group-hover:opacity-100 transition">
#
</a>
)}
</h3>
)
}
export default H3
@@ -0,0 +1,17 @@
import { getAnchor, removeAnchor } from './CustomMDX.utils'
const H4 = ({ children }) => {
const anchor = getAnchor(children)
const link = `#${anchor}`
return (
<h4 id={anchor} className="group">
{removeAnchor(children)}
{anchor && (
<a href={link} className="opacity-0 group-hover:opacity-100 transition">
#
</a>
)}
</h4>
)
}
export default H4
@@ -0,0 +1,4 @@
import H3 from './H3'
import H4 from './H4'
export { H3, H4 }
@@ -0,0 +1,45 @@
import { useTheme } from '~/components/Providers'
import { IconSun, IconMoon } from '@supabase/ui'
function DarkModeToggle() {
const { isDarkMode, toggleTheme } = useTheme()
const toggleDarkMode = () => {
localStorage.setItem('supabaseDarkMode', (!isDarkMode).toString())
toggleTheme()
const key = localStorage.getItem('supabaseDarkMode')
document.documentElement.className = key === 'true' ? 'dark' : ''
}
return (
<div className="flex items-center">
<IconSun className="text-scale-900" strokeWidth={2} />
<button
type="button"
aria-pressed="false"
className={`
relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent
transition-colors duration-200 ease-in-out focus:outline-none ${
isDarkMode ? 'bg-scale-500' : 'bg-scale-900'
} mx-5
`}
onClick={() => toggleDarkMode()}
>
<span className="sr-only">Toggle Themes</span>
<span
aria-hidden="true"
className={`
${
isDarkMode ? 'translate-x-5' : 'translate-x-0'
} dark:bg-scale-300 inline-block h-5 w-5
transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out
`}
/>
</button>
<IconMoon className="text-scale-900" strokeWidth={2} />
</div>
)
}
export default DarkModeToggle
+103 -99
View File
@@ -1,128 +1,132 @@
import Image from 'next/image'
import FooterLinks from 'data/footer.json'
import SectionContainer from './SectionContainer'
import DarkModeToggle from './DarkModeToggle'
import Link from 'next/link'
import footer from '../data/footer.json'
import { useTheme } from './Providers'
import { Badge } from 'ui'
import Image from 'next/image'
import * as supabaseLogoWordmarkDark from 'common/assets/images/supabase-logo-wordmark--dark.png'
import * as supabaseLogoWordmarkLight from 'common/assets/images/supabase-logo-wordmark--light.png'
const Footer = () => {
const { isDarkMode } = useTheme()
return (
<footer
className="border-scale-400 dark:bg-scale-200 border-t bg-white p-10"
className="border-scale-500 dark:border-scale-600 border-t"
aria-labelledby="footerHeading"
>
<h2 id="footerHeading" className="sr-only">
Footer
</h2>
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
<div className="space-y-8 xl:col-span-1">
<Link href="/">
<a>
<Image
src={isDarkMode ? `/supabase-dark.svg` : `/supabase-light.svg`}
alt="Supabase"
width={160}
height={22}
/>
</a>
</Link>
<div className="flex space-x-5">
<a
href="https://twitter.com/supabase"
target="_blank"
rel="noreferrer"
className="text-scale-900 hover:text-scale-1100"
>
<span className="sr-only">Twitter</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
</svg>
</a>
<a
href="https://github.com/supabase"
target="_blank"
rel="noreferrer"
className="text-scale-900 hover:text-scale-1100"
>
<span className="sr-only">GitHub</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path
fillRule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clipRule="evenodd"
<SectionContainer>
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
<div className="space-y-8 xl:col-span-1">
<Link href="#" as="/">
<a className="w-40">
<Image
src={isDarkMode ? supabaseLogoWordmarkDark : supabaseLogoWordmarkLight}
width={160}
height={30}
alt="Supabase"
/>
</svg>
</a>
</a>
</Link>
<div className="flex space-x-5">
<a
href="https://twitter.com/supabase"
className="text-scale-900 hover:text-scale-1200 transition"
>
<span className="sr-only">Twitter</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
</svg>
</a>
<a
href="https://discord.supabase.com/"
target="_blank"
rel="noreferrer"
className="text-scale-900 hover:text-scale-1100"
>
<span className="sr-only">Discord</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 71 55" aria-hidden="true">
<path
fillRule="evenodd"
d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"
clipRule="evenodd"
/>
</svg>
</a>
<a
href="https://github.com/supabase"
className="text-scale-900 hover:text-scale-1200 transition"
>
<span className="sr-only">GitHub</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path
fillRule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clipRule="evenodd"
/>
</svg>
</a>
<a
href="https://youtube.com/c/supabase"
target="_blank"
rel="noreferrer"
className="text-scale-900 hover:text-scale-1100"
>
<span className="sr-only">Youtube</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 576 512" aria-hidden="true">
<path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z" />
</svg>
</a>
<a
href="https://discord.supabase.com/"
className="text-scale-900 hover:text-scale-1200 transition"
>
<span className="sr-only">Discord</span>
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 71 55" aria-hidden="true">
<path
fillRule="evenodd"
d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"
clipRule="evenodd"
/>
</svg>
</a>
<a
href="https://youtube.com/c/supabase"
className="text-scale-900 hover:text-scale-1200 transition"
>
<span className="sr-only">Youtube</span>
<svg
className="h-6 w-6"
fill="currentColor"
viewBox="0 0 576 512"
aria-hidden="true"
>
<path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z" />
</svg>
</a>
</div>
</div>
</div>
<div className="mt-12 grid grid-cols-1 gap-8 xl:col-span-2 xl:mt-0">
<div className="grid grid-cols-2 gap-8 md:grid-cols-4">
{footer.map((segment: any) => {
return (
<div key={`footer_${segment.title}`}>
<h3 className="text-scale-900 dark:text-scale-800 text-sm">{segment.title}</h3>
<ul className="mt-4 space-y-2">
{segment.links.map((link: any, idx: number) => (
<li key={`${segment.title}_link_${idx}`}>
<Link href={link.url}>
<div className="mt-12 grid grid-cols-1 gap-8 xl:col-span-2 xl:mt-0">
<div className="grid grid-cols-2 gap-8 md:grid-cols-4">
{FooterLinks.map((segment: any) => {
return (
<div key={`footer_${segment.title}`}>
<h6 className="text-scale-1200 overwrite text-base">{segment.title}</h6>
<ul className="mt-4 space-y-2">
{segment.links.map((link: any, idx: number) => (
<li key={`${segment.title}_link_${idx}`}>
<a
className={`text-sm ${
href={link.url}
className={`text-sm transition-colors ${
link.url
? 'text-scale-1000 dark:text-scale-1000'
: 'text-scale-300 dark:text-scale-300'
} hover:text-brand-900 dark:hover:text-brand-1100 transition`}
? 'text-scale-1100 hover:text-scale-1200 '
: 'text-scale-900 hover:text-scale-900'
} `}
>
{link.text}
{!link.url && (
<span className="dark:text-dark-300 block text-sm text-gray-300">
Coming soon
</span>
<div className="ml-2 inline text-xs xl:ml-0 xl:block 2xl:ml-2 2xl:inline">
<Badge color="scale" size="small">
Coming soon
</Badge>
</div>
)}
</a>
</Link>
</li>
))}
</ul>
</div>
)
})}
</li>
))}
</ul>
</div>
)
})}
</div>
</div>
</div>
</div>
<div className="dark:border-scale-400 mt-32 flex justify-between border-t pt-8">
<p className="dark:text-dark-400 text-scale-800 mb-0 self-center text-sm">
&copy; {new Date().getFullYear()} Supabase.
</p>
</div>
<div className="border-scale-500 dark:border-scale-600 mt-32 flex justify-between border-t pt-8">
<small className="small">&copy; Supabase Inc</small>
<DarkModeToggle />
</div>
</SectionContainer>
</footer>
)
}
+99
View File
@@ -0,0 +1,99 @@
import ButtonCard from './ButtonCard'
const Frameworks = () => {
const frameworks = [
{
name: 'Angular',
// logo: AngularLogo,
href: '/guides/with-angular',
},
{
name: 'Expo',
// logo: ExpoLogo,
href: '/guides/with-expo',
},
{
name: 'Flutter',
// logo: FlutterLogo,
href: '/guides/with-flutter',
},
{
name: 'JavaScript',
// logo: JavascriptLogo,
href: '/reference/javascript/installing#javascript',
},
{
name: 'Next.js',
themed: true,
logo: {
dark: '/img/libraries/nextjs-dark-icon.svg',
light: '/img/libraries/nextjs-light-icon.svg',
},
href: '/guides/with-nextjs',
},
{
name: 'React',
// logo: ReactLogo,
href: '/guides/with-react',
},
{
name: 'RedwoodJS',
// logo: RedwoodJsLogo,
href: '/guides/with-redwoodjs',
},
{
name: 'SolidJS',
// logo: SolidJSLogo,
href: '/guides/with-solidjs',
},
{
name: 'Svelte',
// logo: SvelteLogo,
href: '/guides/with-svelte',
},
{
name: 'Vue',
// logo: VuejsLogo,
href: '/guides/with-vue-3',
},
]
return (
<div className="grid grid-cols-12 gap-4">
{frameworks.map((x) => (
<div key={x.name} className="col-span-3">
<ButtonCard
layout="horizontal"
to={x.href}
title={x.name}
// icon={
// x.logo && !x.themed ? (
// <x.logo
// width="20"
// alt={x.name}
// style={{ display: 'block', maxHeight: 20, minWidth: 20 }}
// />
// ) : (
// <ThemedImage
// style={{
// display: 'block',
// maxHeight: 20,
// minWidth: 20,
// margin: 0,
// }}
// alt={x.name}
// width="20"
// sources={{
// light: useBaseUrl(x.logo.light),
// dark: useBaseUrl(x.logo.dark),
// }}
// />
// )
// }
/>
</div>
))}
</div>
)
}
export default Frameworks
@@ -0,0 +1,313 @@
import SupabaseJsV1Nav from 'data/nav/supabase-js/v1'
import SupabaseJsV2Nav from 'data/nav/supabase-js/v2'
import SupabaseDartV0Nav from 'data/nav/supabase-dart/v0'
import SupabaseDartV1Nav from 'data/nav/supabase-dart/v1'
import SupabaseCLINav from 'data/nav/supabase-cli'
import SupabaseAPINav from 'data/nav/supabase-api'
import AuthServerNav from 'data/nav/auth-server'
import StorageServerNav from 'data/nav/storage-server'
export interface NavMenu {
[key: string]: NavMenuGroup[]
}
export interface NavMenuGroup {
label: string
items: NavMenuSection[]
}
export interface NavMenuSection {
name: string
url?: string
items: NavMenuSection[]
}
export const menuItems: NavMenu = {
docs: [
{
label: 'Overview',
items: [
{ name: 'Introduction', url: '/', items: [] },
{ name: 'Features', url: '/guides/features', items: [] },
{ name: 'Architecture', url: '/architecture', items: [] },
],
},
{
label: 'Quickstarts',
items: [
{ name: 'Angular', url: '/guides/with-angular', items: [] },
{ name: 'Expo', url: '/guides/with-expo', items: [] },
{ name: 'Flutter', url: '/guides/with-flutter', items: [] },
{ name: 'Ionic Angular', url: '/guides/with-ionic-angular', items: [] },
{ name: 'Ionic React', url: '/guides/with-ionic-react', items: [] },
{ name: 'Ionic Vue', url: '/guides/with-ionic-vue', items: [] },
{ name: 'Next.js', url: '/guides/with-nextjs', items: [] },
{ name: 'Nuxt 3', url: '/guides/with-nuxt-3', items: [] },
{ name: 'React', url: '/guides/with-react', items: [] },
{ name: 'RedwoodJS', url: '/guides/with-redwoodjs', items: [] },
{ name: 'SolidJS', url: '/guides/with-solidjs', items: [] },
{ name: 'Svelte', url: '/guides/with-svelte', items: [] },
{ name: 'SvelteKit', url: '/guides/with-sveltekit', items: [] },
{ name: 'Vue 3', url: '/guides/with-vue-3', items: [] },
],
},
{
label: 'CLI',
items: [
{ name: 'Overview', url: '/guides/cli', items: [] },
{ name: 'Local Development', url: '/guides/cli/local-development', items: [] },
{ name: 'Managing Environments', url: '/guides/cli/managing-environments', items: [] },
],
},
{
label: 'Auth',
items: [
{ name: 'Overview', url: '/guides/auth', items: [] },
{
name: 'Authentication',
url: undefined,
items: [
{ name: 'Login with Email', url: '/guides/auth/auth-email', items: [] },
{ name: 'Login with Magic Link', url: '/guides/auth/auth-magic-link', items: [] },
{ name: 'Login with Apple', url: '/guides/auth/auth-apple', items: [] },
{ name: 'Login with Azure', url: '/guides/auth/auth-azure', items: [] },
{ name: 'Login with Bitbucket', url: '/guides/auth/auth-bitbucket', items: [] },
{ name: 'Login with Discord', url: '/guides/auth/auth-discord', items: [] },
{ name: 'Login with Facebook', url: '/guides/auth/auth-facebook', items: [] },
{ name: 'Login with Github', url: '/guides/auth/auth-github', items: [] },
{ name: 'Login with Gitlab', url: '/guides/auth/auth-gitlab', items: [] },
{ name: 'Login with Google', url: '/guides/auth/auth-google', items: [] },
{ name: 'Login with Keycloak', url: '/guides/auth/auth-keycloak', items: [] },
{ name: 'Login with LinkedIn', url: '/guides/auth/auth-linkedin', items: [] },
{ name: 'Login with Notion', url: '/guides/auth/auth-notion', items: [] },
{ name: 'Login with Slack', url: '/guides/auth/auth-slack', items: [] },
{ name: 'Login with Spotify', url: '/guides/auth/auth-spotify', items: [] },
{ name: 'Login with Twitch', url: '/guides/auth/auth-twitch', items: [] },
{ name: 'Login with Twitter', url: '/guides/auth/auth-twitter', items: [] },
{ name: 'Login with WorkOS', url: '/guides/auth/auth-workos', items: [] },
{ name: 'Phone Auth with Twilio', url: '/guides/auth/twilio', items: [] },
{ name: 'Phone Auth with Vonage', url: '/guides/auth/vonage', items: [] },
{ name: 'Phone Auth with MessageBird', url: '/guides/auth/messagebird', items: [] },
],
},
{
name: 'Authorization',
url: undefined,
items: [
{ name: 'Row Level Security', url: '/guides/auth/row-level-security', items: [] },
{ name: 'Managing User Data', url: '/guides/auth/managing-user-data', items: [] },
{ name: 'Enable Captcha Protection', url: '/guides/auth/auth-captcha', items: [] },
{ name: 'Server-side Rendering', url: '/guides/auth/server-side-rendering', items: [] },
{ name: 'Multi-Factor Authentication', url: '/guides/auth/auth-mfa', items: [] },
],
},
{
name: 'Auth Helpers',
url: undefined,
items: [
{ name: 'Overview', url: '/guides/auth/auth-helpers', items: [] },
{ name: 'Auth UI', url: '/guides/auth/auth-helpers/auth-ui', items: [] },
{ name: 'Next.js', url: '/guides/auth/auth-helpers/nextjs', items: [] },
{ name: 'SvelteKit', url: '/guides/auth/auth-helpers/sveltekit', items: [] },
],
},
{
name: 'Deep Dive',
url: undefined,
items: [
{ name: 'Part One: JWTs', url: 'learn/auth-deep-dive/auth-deep-dive-jwts', items: [] },
{
name: 'Part Two: Row Level Security',
url: 'learn/auth-deep-dive/auth-row-level-security',
items: [],
},
{ name: 'Part Three: Policies', url: 'learn/auth-deep-dive/auth-policies', items: [] },
{ name: 'Part Four: GoTrue', url: 'learn/auth-deep-dive/auth-gotrue', items: [] },
{
name: 'Part Fibe: Google OAuth',
url: 'learn/auth-deep-dive/auth-google-oauth',
items: [],
},
],
},
],
},
{
label: 'APIs',
items: [
{ name: 'Overview', url: '/guides/api', items: [] },
{ name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
],
},
{
label: 'Database',
items: [
{ name: 'Overview', url: '/guides/database', items: [] },
{ name: 'Database Connections', url: '/guides/database/connecting-to-postgres', items: [] },
{ name: 'Tables and Data', url: '/guides/database/tables', items: [] },
{ name: 'Database Functions', url: '/guides/database/functions', items: [] },
{ name: 'Full Text Search', url: '/guides/database/full-text-search', items: [] },
{
name: 'Migrating Between Projects',
url: '/guides/platform/migrating-and-upgrading-projects',
items: [],
},
{
name: 'Extensions',
url: undefined,
items: [
{ name: 'Overview', url: '/guides/database/extensions', items: [] },
{
name: 'plv8: Javascript Language',
url: '/guides/database/extensions/plv8',
items: [],
},
{ name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
{ name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] },
{
name: 'uuid-ossp: Unique Identifiers',
url: '/guides/database/extensions/uuid-ossp',
items: [],
},
],
},
{
name: 'Configuration',
url: undefined,
items: [
{ name: 'Timeouts', url: '/guides/database/timeouts', items: [] },
{ name: 'Replication', url: '/guides/database/replication', items: [] },
{ name: 'Passwords', url: '/guides/database/managing-passwords', items: [] },
{ name: 'Timezones', url: '/guides/database/managing-timezones', items: [] },
],
},
],
},
{
label: 'Edge Functions',
items: [
{ name: 'Overview', url: '/guides/functions', items: [] },
{ name: 'Auth', url: '/guides/functions/auth', items: [] },
{ name: 'Examples', url: '/guides/functions/examples', items: [] },
{ name: 'CI/CD Workflow', url: '/guides/functions/cicd-workflow', items: [] },
],
},
{
label: 'Realtime',
items: [
{ name: 'Overview', url: '/guides/realtime', items: [] },
{ name: 'Quickstart', url: '/guides/realtime/quickstart', items: [] },
{ name: 'Postgres CDC', url: '/guides/realtime/postgres-cdc', items: [] },
],
},
{
label: 'Storage',
items: [
{ name: 'Overview', url: '/guides/storage', items: [] },
{ name: 'CDN', url: '/guides/storage-cdn', items: [] },
],
},
{
label: 'Platform',
items: [
{ name: 'Overview', url: '/guides/hosting/platform', items: [] },
{ name: 'Custom Domains', url: '/guides/platform/custom-domains', items: [] },
{ name: 'Disk Space Usage', url: '/guides/platform/disk-usage', items: [] },
{ name: 'Logging', url: '/guides/platform/logs', items: [] },
{ name: 'Metrics', url: '/guides/platform/metrics', items: [] },
{ name: 'Performance', url: '/guides/platform/performance', items: [] },
{ name: 'Permissions', url: '/guides/platform/permissions', items: [] },
{ name: 'Production Readiness', url: '/guides/platform/going-into-prod', items: [] },
],
},
{
label: 'Self Hosting',
items: [
{ name: 'Overview', url: '/guides/hosting/overview', items: [] },
{ name: 'Docker', url: '/guides/hosting/docker', items: [] },
],
},
{
label: 'Migrate to Supabase',
items: [
{ name: 'Firebase Auth', url: '/guides/migrations/firebase-auth', items: [] },
{ name: 'Firestore Data', url: '/guides/migrations/firestore-data', items: [] },
{ name: 'Firebase Storage', url: '/guides/migrations/firebase-storage', items: [] },
{ name: 'Herokuy', url: '/guides/migrations/heroku', items: [] },
],
},
{
label: 'Integrations',
items: [
{ name: 'Supabase Marketplace', url: '/guides/integrations/integrations', items: [] },
{
name: 'Auth',
url: undefined,
items: [
{ name: 'Auth0', url: '/guides/integration/auth0', items: [] },
{ name: 'Authsignal', url: '/guides/integration/authsignal', items: [] },
{ name: 'Clerk', url: '/guides/integration/clerk', items: [] },
{ name: 'keyri', url: '/guides/integration/keyri', items: [] },
{ name: 'Stytch', url: '/guides/integration/stytch', items: [] },
{ name: 'SuperTokens', url: '/guides/integration/supertokens', items: [] },
],
},
{
name: 'Caching / Offline-first',
url: undefined,
items: [{ name: 'Polyscale', url: '/guides/integrations/polyscale', items: [] }],
},
{
name: 'Developer Tools',
url: undefined,
items: [
{ name: 'pgMustard', url: '/guides/integrations/pgmustard', items: [] },
{ name: 'Prisma', url: '/guides/integrations/prisma', items: [] },
{ name: 'Sequin', url: '/guides/integrations/sequin', items: [] },
{ name: 'Snaplet', url: '/guides/integrations/snaplet', items: [] },
{ name: 'Vercel', url: '/guides/integrations/vercel', items: [] },
],
},
{
name: 'Low-code',
url: undefined,
items: [
{ name: 'Appsmith', url: '/guides/integrations/appsmith', items: [] },
{ name: 'Dashibase', url: '/guides/integrations/dashibase', items: [] },
{ name: 'DhiWise', url: '/guides/integrations/dhiwise', items: [] },
{ name: 'Directus', url: '/guides/integrations/directus', items: [] },
{ name: 'Draftbit', url: '/guides/integrations/draftbit', items: [] },
{ name: 'Plasmic', url: '/guides/integrations/plasmic', items: [] },
],
},
],
},
],
reference: [
{
label: 'Official',
items: [
{ name: 'Reference Documentation', url: '/reference', items: [] },
{ name: 'Supabase Javascript Library', url: '/reference/javascript', items: [] },
{ name: 'Supabase Flutter Library', url: '/reference/dart', items: [] },
{ name: 'Supabase CLI', url: '/reference/cli', items: [] },
{ name: 'Supabase API', url: '/reference/api', items: [] },
],
},
{
label: 'Self-hosting',
items: [
{ name: 'Auth Server', url: '/reference/auth', items: [] },
{ name: 'Storage Server', url: '/reference/storage', items: [] },
],
},
],
'reference/javascript': SupabaseJsV2Nav,
'reference/javascript/v1': SupabaseJsV1Nav,
'reference/dart': SupabaseDartV1Nav,
'reference/dart/v0': SupabaseDartV0Nav,
'reference/cli': SupabaseCLINav,
'reference/api': SupabaseAPINav,
'reference/auth': AuthServerNav,
'reference/storage': StorageServerNav,
}
@@ -0,0 +1,157 @@
import Image from 'next/image'
import Link from 'next/link'
import { useState, useEffect } from 'react'
import { IconMenu, IconSearch, Input, IconCommand, Button, IconMoon, IconSun } from 'ui'
import { useTheme } from '../Providers'
const NavBar = ({ currentPage }: { currentPage: string }) => {
const { isDarkMode, toggleTheme } = useTheme()
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [isDarkMode])
const pageLinks = [
{ text: 'Guides', key: 'docs', link: '/' },
{ text: 'Reference', key: 'reference', link: '/reference' },
]
const toggleDarkMode = () => {
localStorage.setItem('supabaseDarkMode', (!isDarkMode).toString())
toggleTheme()
const key = localStorage.getItem('supabaseDarkMode')
document.documentElement.className = key === 'true' ? 'dark' : ''
}
return (
<nav
className={[
'sticky top-0 z-10 flex items-center justify-between',
'h-[60px] border-b bg-white p-4 backdrop-blur backdrop-filter',
'dark:border-scale-400 dark:bg-scale-200',
].join(' ')}
>
<div className="flex items-center">
<button className="mr-4 block stroke-2 lg:hidden">
<IconMenu className="text-scale-1100" />
</button>
{mounted && (
<Link href="/">
<a className="flex items-center">
<Image
className="cursor-pointer"
src={isDarkMode ? '/docs/supabase-dark.svg' : '/docs/supabase-light.svg'}
width={124}
height={24}
alt="Supabase Logo"
/>
</a>
</Link>
)}
<nav className="ml-8 hidden lg:flex">
<ul className="hidden space-x-8 lg:flex">
{pageLinks.map((p) => (
<li key={`${p.text}-${p.link}`}>
<Link href={p.link}>
<a
className={`text-sm ${
currentPage.includes(p.key) ? 'text-brand-900' : 'text-scale-1100'
}`}
>
{p.text}
</a>
</Link>
</li>
))}
</ul>
</nav>
</div>
<div className="flex items-center space-x-4">
<div className="hidden items-center md:flex">
<ul className="flex items-center">
<li className="px-4">
<a
href="https://app.supabase.com"
className="text-scale-1100 text-sm"
target="_blank"
rel="noreferrer noopener"
>
Dashboard
</a>
</li>
<li className="px-4">
<a
href="https://github.com/supabase/supabase"
target="_blank"
rel="noreferrer noopener"
>
<div
className="h-4 w-4 !bg-no-repeat !bg-center"
style={{
background: isDarkMode
? "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\") 50% no-repeat"
: "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")",
}}
/>
</a>
</li>
<li className="px-4">
<a
href="https://discord.supabase.com"
rel="noreferrer noopener"
target="_blank"
className="text-scale-1100"
>
<div
className="h-4 w-4 !bg-no-repeat !bg-center"
style={{
background: isDarkMode
? "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 71 55' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23a)'%3E%3Cpath d='M60.105 4.898A58.55 58.55 0 0 0 45.653.415a.22.22 0 0 0-.233.11 40.784 40.784 0 0 0-1.8 3.697c-5.456-.817-10.886-.817-16.23 0-.485-1.164-1.201-2.587-1.828-3.697a.228.228 0 0 0-.233-.11 58.386 58.386 0 0 0-14.451 4.483.207.207 0 0 0-.095.082C1.578 18.73-.944 32.144.293 45.39a.244.244 0 0 0 .093.167c6.073 4.46 11.955 7.167 17.729 8.962a.23.23 0 0 0 .249-.082 42.08 42.08 0 0 0 3.627-5.9.225.225 0 0 0-.123-.312 38.772 38.772 0 0 1-5.539-2.64.228.228 0 0 1-.022-.378c.372-.279.744-.569 1.1-.862a.22.22 0 0 1 .23-.03c11.619 5.304 24.198 5.304 35.68 0a.219.219 0 0 1 .233.027c.356.293.728.586 1.103.865a.228.228 0 0 1-.02.378 36.384 36.384 0 0 1-5.54 2.637.227.227 0 0 0-.121.315 47.249 47.249 0 0 0 3.624 5.897.225.225 0 0 0 .249.084c5.801-1.794 11.684-4.502 17.757-8.961a.228.228 0 0 0 .092-.164c1.48-15.315-2.48-28.618-10.497-40.412a.18.18 0 0 0-.093-.084Zm-36.38 32.427c-3.497 0-6.38-3.211-6.38-7.156 0-3.944 2.827-7.156 6.38-7.156 3.583 0 6.438 3.24 6.382 7.156 0 3.945-2.827 7.156-6.381 7.156Zm23.593 0c-3.498 0-6.38-3.211-6.38-7.156 0-3.944 2.826-7.156 6.38-7.156 3.582 0 6.437 3.24 6.38 7.156 0 3.945-2.798 7.156-6.38 7.156Z' fill='%23fff'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Cpath fill='%23fff' d='M0 0h71v55H0z'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\") 50% no-repeat"
: "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 71 55' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23a)'%3E%3Cpath d='M60.105 4.898A58.55 58.55 0 0 0 45.653.415a.22.22 0 0 0-.233.11 40.784 40.784 0 0 0-1.8 3.697c-5.456-.817-10.886-.817-16.23 0-.485-1.164-1.201-2.587-1.828-3.697a.228.228 0 0 0-.233-.11 58.386 58.386 0 0 0-14.451 4.483.207.207 0 0 0-.095.082C1.578 18.73-.944 32.144.293 45.39a.244.244 0 0 0 .093.167c6.073 4.46 11.955 7.167 17.729 8.962a.23.23 0 0 0 .249-.082 42.08 42.08 0 0 0 3.627-5.9.225.225 0 0 0-.123-.312 38.772 38.772 0 0 1-5.539-2.64.228.228 0 0 1-.022-.378c.372-.279.744-.569 1.1-.862a.22.22 0 0 1 .23-.03c11.619 5.304 24.198 5.304 35.68 0a.219.219 0 0 1 .233.027c.356.293.728.586 1.103.865a.228.228 0 0 1-.02.378 36.384 36.384 0 0 1-5.54 2.637.227.227 0 0 0-.121.315 47.249 47.249 0 0 0 3.624 5.897.225.225 0 0 0 .249.084c5.801-1.794 11.684-4.502 17.757-8.961a.228.228 0 0 0 .092-.164c1.48-15.315-2.48-28.618-10.497-40.412a.18.18 0 0 0-.093-.084Zm-36.38 32.427c-3.497 0-6.38-3.211-6.38-7.156 0-3.944 2.827-7.156 6.38-7.156 3.583 0 6.438 3.24 6.382 7.156 0 3.945-2.827 7.156-6.381 7.156Zm23.593 0c-3.498 0-6.38-3.211-6.38-7.156 0-3.944 2.826-7.156 6.38-7.156 3.582 0 6.437 3.24 6.38 7.156 0 3.945-2.798 7.156-6.38 7.156Z' fill='%2323272A'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Cpath fill='%23fff' d='M0 0h71v55H0z'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\")",
}}
/>
</a>
</li>
<li className="px-4">
<a href="https://twitter.com/supabase" target="_blank" rel="noreferrer noopener">
<div
className="h-4 w-4 !bg-no-repeat !bg-center"
style={{
background: isDarkMode
? "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 335 276' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' d='M302 70A195 195 0 0 1 3 245a142 142 0 0 0 97-30 70 70 0 0 1-58-47 70 70 0 0 0 31-2 70 70 0 0 1-57-66 70 70 0 0 0 28 5 70 70 0 0 1-18-90 195 195 0 0 0 141 72 67 67 0 0 1 116-62 117 117 0 0 0 43-17 65 65 0 0 1-31 38 117 117 0 0 0 39-11 65 65 0 0 1-32 35'/%3E%3C/svg%3E\") 50% no-repeat"
: "url(\"data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 335 276' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M302 70A195 195 0 0 1 3 245a142 142 0 0 0 97-30 70 70 0 0 1-58-47 70 70 0 0 0 31-2 70 70 0 0 1-57-66 70 70 0 0 0 28 5 70 70 0 0 1-18-90 195 195 0 0 0 141 72 67 67 0 0 1 116-62 117 117 0 0 0 43-17 65 65 0 0 1-31 38 117 117 0 0 0 39-11 65 65 0 0 1-32 35'/%3E%3C/svg%3E\")",
}}
/>
</a>
</li>
<li className="px-4">
<div className="cursor-pointer" onClick={toggleDarkMode}>
{isDarkMode ? (
<IconMoon size={18} strokeWidth={2} className="text-scale-1200" />
) : (
<IconSun size={18} strokeWidth={2} className="text-scale-1200" />
)}
</div>
</li>
</ul>
</div>
<Input
placeholder="Search"
icon={<IconSearch />}
type="search"
actions={[
<Button disabled key="icon-command" type="default" size="tiny">
<IconCommand size="tiny" />
</Button>,
<Button disabled key="icon-letter" type="default" size="tiny">
K
</Button>,
]}
/>
</div>
</nav>
)
}
export default NavBar
@@ -0,0 +1,199 @@
import Link from 'next/link'
import Image from 'next/image'
import { useRouter } from 'next/router'
import { IconChevronRight, IconArrowLeft } from '~/../../packages/ui'
import { NavMenuGroup, NavMenuSection } from './Nav.constants'
import * as Accordion from '@radix-ui/react-accordion'
const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
const { asPath } = useRouter()
const pathSegments = asPath.split('/')
const isInReferencePages = pathSegments.includes('reference') && pathSegments.length >= 3
const references = {
javascript: { name: 'supabase-js', icon: '/docs/img/libraries/javascript-icon.svg' },
dart: { name: 'Flutter', icon: '/docs/img/libraries/dart-icon.svg' },
cli: { name: 'CLI', icon: '/docs/img/libraries/cli-icon.svg' },
api: { name: 'API', icon: '/docs/img/libraries/api-icon.svg' },
}
const referenceMeta = pathSegments.length >= 3 ? references[pathSegments[2]] : undefined
const currentSection: NavMenuGroup = menuItems.find((group) => {
const foundItem = group.items.find((section) => {
if (section.items.length > 0) {
const foundSubItem = section.items.find((item) => {
if (item.url === asPath) return item
})
if (foundSubItem) return section
} else {
if (section.url === asPath) return section
}
})
if (foundItem) return group
})
const currentSubSection: NavMenuSection =
currentSection !== undefined
? currentSection.items.find((section) => {
if (section.items.length === 0) {
return undefined
} else {
return section.items.find((item) => {
if (item.url === asPath) return item
})
}
})
: undefined
console.log({ currentSection, currentSubSection })
return (
<div
className="dark:bg-scale-200 dark:border-scale-400 sidebar-width sticky top-0
h-screen overflow-y-scroll border-r py-8 px-6 sidebar-menu-container"
>
{isInReferencePages && (
<>
<Link href="/reference">
<a>
<div className="flex items-center space-x-4 opacity-75 hover:opacity-100 transition">
<IconArrowLeft size={16} strokeWidth={2} className="text-scale-1200" />
<span className="text-sm text-scale-1200">All Reference Docs</span>
</div>
</a>
</Link>
{referenceMeta !== undefined && (
<div className="my-5 flex items-center space-x-4">
<div className="h-10 w-10 rounded bg-scale-500 flex items-center justify-center">
<Image
className="rounded"
width={24}
height={24}
alt={referenceMeta.name}
src={referenceMeta.icon}
/>
</div>
<p className="text-scale-1200 font-bold">{referenceMeta.name}</p>
</div>
)}
</>
)}
{menuItems.length === 1 ? (
<div className="my-2">
{menuItems[0].items.map((item) => (
<Link href={item.url}>
<a>
<div
key={item.name}
className={[
'py-1.5 px-5 rounded text-sm transition',
`${
item.url === asPath
? 'bg-scale-400 text-brand-900'
: 'text-scale-1100 hover:text-scale-1200'
}`,
].join(' ')}
>
{item.name}
</div>
</a>
</Link>
))}
</div>
) : (
<Accordion.Root
collapsible
type="single"
defaultValue={currentSection?.label}
className="w-full space-y-0.5"
>
{menuItems.map((group: NavMenuGroup) => (
<Accordion.Item key={group.label} value={group.label}>
<Accordion.Trigger className="w-full flex items-center space-x-2 py-1.5">
<IconChevronRight
className="transition text-scale-1000 data-open-parent:rotate-90"
size={14}
strokeWidth={2}
/>
<span className="text-scale-1200 text-sm group-hover:text-brand-900 transition">
{group.label}
</span>
</Accordion.Trigger>
<Accordion.Content className="transition my-2 data-open:animate-slide-down data-closed:animate-slide-up">
{group.items.map((section: NavMenuSection) => {
if (section.items.length === 0) {
return (
<Link href={section.url}>
<a>
<div
key={section.name}
className={[
'py-1.5 px-5 rounded text-sm transition',
`${
section.url === asPath
? 'bg-scale-400 text-brand-900'
: 'text-scale-1100 hover:text-scale-1200'
}`,
].join(' ')}
>
{section.name}
</div>
</a>
</Link>
)
} else {
return (
<Accordion.Root
collapsible
key={section.name}
type="single"
className="space-y-0.5"
defaultValue={currentSubSection?.name}
>
<Accordion.Item value={section.name}>
<Accordion.Trigger className="flex items-center space-x-2 px-4 py-1.5">
<IconChevronRight
className="transition text-scale-1000 data-open-parent:rotate-90"
size={14}
strokeWidth={2}
/>
<span className="text-scale-1200 text-sm group-hover:text-brand-900 transition">
{section.name}
</span>
</Accordion.Trigger>
<Accordion.Content className="my-2 data-open:animate-slide-down data-closed:animate-slide-up">
{section.items.map((item: NavMenuSection) => (
<Link href={item.url}>
<a>
<div
key={item.name}
className={[
'py-1.5 ml-4 px-5 rounded text-sm transition',
`${
item.url === asPath
? 'bg-scale-400 text-brand-900'
: 'text-scale-1100 hover:text-scale-1200'
}`,
].join(' ')}
>
{item.name}
</div>
</a>
</Link>
))}
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
)
}
})}
</Accordion.Content>
</Accordion.Item>
))}
</Accordion.Root>
)}
</div>
)
}
export default SideBar
+209
View File
@@ -0,0 +1,209 @@
import { useState, useCallback, useRef, createContext, useContext, useEffect } from 'react'
import { createPortal } from 'react-dom'
import Link from 'next/link'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { DocSearchModal } from '@docsearch/react'
import clsx from 'clsx'
import { useActionKey } from '~/hooks/useActionKey'
const INDEX_NAME = 'tailwindcss_dev'
const API_KEY = '5fc87cef58bb80203d2207578309fab6'
const APP_ID = 'KNPXZI5B0M'
const SearchContext = createContext(null)
export function SearchProvider({ children }: any) {
const router = useRouter()
const [isOpen, setIsOpen] = useState(false)
const [initialQuery, setInitialQuery] = useState(null)
const onOpen = useCallback(() => {
setIsOpen(true)
}, [setIsOpen])
const onClose = useCallback(() => {
setIsOpen(false)
}, [setIsOpen])
const onInput = useCallback(
(e) => {
setIsOpen(true)
setInitialQuery(e.key)
},
[setIsOpen, setInitialQuery]
)
useDocSearchKeyboardEvents({
isOpen,
onOpen,
onClose,
// @ts-ignore
onInput,
})
return (
<>
<Head>
<link rel="preconnect" href={`https://${APP_ID}-dsn.algolia.net`} crossOrigin="true" />
</Head>
<SearchContext.Provider
// @ts-ignore
value={{
isOpen,
onOpen,
onClose,
onInput,
}}
>
{children}
</SearchContext.Provider>
{isOpen &&
createPortal(
<DocSearchModal
// @ts-ignore
initialQuery={initialQuery}
initialScrollY={window.scrollY}
searchParameters={{
facetFilters: 'version:v3',
distinct: 1,
}}
placeholder="Search documentation"
onClose={onClose}
indexName={INDEX_NAME}
apiKey={API_KEY}
appId={APP_ID}
// @ts-ignore
navigator={{
navigate({ suggestionUrl }) {
setIsOpen(false)
router.push(suggestionUrl)
},
}}
hitComponent={Hit}
transformItems={(items) => {
return items.map((item, index) => {
// We transform the absolute URL into a relative URL to
// leverage Next's preloading.
const a = document.createElement('a')
a.href = item.url
const hash = a.hash === '#content-wrapper' ? '' : a.hash
return {
...item,
url: `${a.pathname}${hash}`,
__is_result: () => true,
__is_parent: () => item.type === 'lvl1' && items.length > 1 && index === 0,
__is_child: () =>
item.type !== 'lvl1' &&
items.length > 1 &&
items[0].type === 'lvl1' &&
index !== 0,
__is_first: () => index === 1,
__is_last: () => index === items.length - 1 && index !== 0,
}
})
}}
/>,
document.body
)}
</>
)
}
// @ts-ignore
function Hit({ hit, children }) {
return (
<Link href={hit.url}>
<a
className={clsx({
'DocSearch-Hit--Result': hit.__is_result?.(),
'DocSearch-Hit--Parent': hit.__is_parent?.(),
'DocSearch-Hit--FirstChild': hit.__is_first?.(),
'DocSearch-Hit--LastChild': hit.__is_last?.(),
'DocSearch-Hit--Child': hit.__is_child?.(),
})}
>
{children}
</a>
</Link>
)
}
// @ts-ignore
export function SearchButton({ children, ...props }) {
let searchButtonRef = useRef()
let actionKey = useActionKey()
// @ts-ignore
let { onOpen, onInput } = useContext(SearchContext)
useEffect(() => {
// @ts-ignore
function onKeyDown(event) {
if (searchButtonRef && searchButtonRef.current === document.activeElement && onInput) {
if (/[a-zA-Z0-9]/.test(String.fromCharCode(event.keyCode))) {
onInput(event)
}
}
}
window.addEventListener('keydown', onKeyDown)
return () => {
window.removeEventListener('keydown', onKeyDown)
}
}, [onInput, searchButtonRef])
return (
// @ts-ignore
<button type="button" ref={searchButtonRef} onClick={onOpen} {...props}>
{typeof children === 'function' ? children({ actionKey }) : children}
</button>
)
}
// @ts-ignore
function useDocSearchKeyboardEvents({ isOpen, onOpen, onClose }) {
useEffect(() => {
// @ts-ignore
function onKeyDown(event) {
function open() {
// We check that no other DocSearch modal is showing before opening
// another one.
if (!document.body.classList.contains('DocSearch--active')) {
onOpen()
}
}
if (
(event.keyCode === 27 && isOpen) ||
(event.key === 'k' && (event.metaKey || event.ctrlKey)) ||
(!isEditingContent(event) && event.key === '/' && !isOpen)
) {
event.preventDefault()
if (isOpen) {
onClose()
} else if (!document.body.classList.contains('DocSearch--active')) {
open()
}
}
}
window.addEventListener('keydown', onKeyDown)
return () => {
window.removeEventListener('keydown', onKeyDown)
}
}, [isOpen, onOpen, onClose])
}
// @ts-ignore
function isEditingContent(event) {
let element = event.target
let tagName = element.tagName
return (
element.isContentEditable ||
tagName === 'INPUT' ||
tagName === 'SELECT' ||
tagName === 'TEXTAREA'
)
}
@@ -0,0 +1,19 @@
import classNames from 'classnames'
interface Props {
children: React.ReactNode
className?: string
}
const SectionContainer = ({ children, className }: Props) => (
<div
className={classNames(
`sm:py-18 container relative mx-auto px-6 py-16 md:py-24 lg:px-16 lg:py-24 xl:px-20`,
className
)}
>
{children}
</div>
)
export default SectionContainer
+1 -1
View File
@@ -1,4 +1,4 @@
import { Tabs } from '@supabase/ui'
import { Tabs } from 'ui'
export default function TabPanel(props: { id: string; label: string | undefined; children: any }) {
return (
<Tabs.Panel id={props.id} label={props.label}>
+1 -1
View File
@@ -1,4 +1,4 @@
import { Tabs } from '@supabase/ui'
import { Tabs } from 'ui'
const TabWrapper = (props: any) => {
return (
-26
View File
@@ -1,26 +0,0 @@
import { useTheme } from './Providers'
import { IconSun, IconMoon } from '@supabase/ui'
function DarkModeToggle() {
const { isDarkMode, toggleTheme } = useTheme()
const toggleDarkMode = () => {
localStorage.setItem('supabaseDarkMode', (!isDarkMode).toString())
toggleTheme()
const key = localStorage.getItem('supabaseDarkMode')
document.documentElement.className = key === 'true' ? 'dark' : ''
}
return (
<button onClick={() => toggleDarkMode()}>
{isDarkMode ? (
<IconMoon className="text-scale-1100 stroke-2" />
) : (
<IconSun className="text-scale-1100 stroke-2" />
)}
</button>
)
}
export default DarkModeToggle
+15 -16
View File
@@ -1,22 +1,21 @@
import LinkCard from './LinkCard'
import LinkCardsWrapper from './LinkCardsWrapper'
import { Tabs } from '@supabase/ui'
import Sponsor from './Sponsor'
import SponsorsWrapper from './SponsorsWrapper'
import { Tabs, Alert } from 'ui'
// import Tabs from '@theme/Tabs'
// import TabItem from '@theme/TabItem'
import CodeBlock from './CodeBlock/CodeBlock'
import AuthProviders from './AuthProviders'
import ButtonCard from './ButtonCard'
import Frameworks from './Frameworks'
import { H3, H4 } from './CustomMDX'
const components = {
// LinkCard,
// LinkCardsWrapper,
// SponsorsWrapper,
// Sponsor,
// AuthProviders,
// Tabs: (props: any) => <Tabs {...props} type="underlined" size="small" />,
// TabsPanel: (props: any) => {
// return <Tabs.Panel {...props} />
// },
// code: (props: any) => <CodeBlock {...props} />,
h3: H3,
h4: H4,
Alert,
ButtonCard,
Frameworks,
Tabs,
TabPanel: (props: any) => <Tabs.Panel {...props}>{props.children}</Tabs.Panel>,
code: (props: any) => <CodeBlock {...props} />,
}
export default components
@@ -1,37 +0,0 @@
import Head from 'next/head'
import NavBar from '../nav/NavBar'
import Footer from '../Footer'
const Layout = ({
children,
meta,
currentPage,
}: {
meta: { title: string; description: string }
children: React.ReactNode
currentPage: string
}) => {
return (
<>
<Head>
<title>{meta?.title} | Supabase</title>
<meta name="description" content={meta?.description} />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="icon" href="/favicon.ico" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content={meta?.title} />
<meta property="og:description" content={meta?.description} />
<meta property="og:title" content={meta?.title} />
</Head>
<main>
<NavBar currentPage={currentPage} />
<article className="text-scale-1200 mx-4 md:mx-8 xl:mx-auto xl:max-w-7xl">
{children}
</article>
<Footer />
</main>
</>
)
}
export default Layout
-103
View File
@@ -1,103 +0,0 @@
import { useState, useEffect } from 'react'
import {
IconMenu,
IconGitHub,
IconTwitter,
IconSearch,
Input,
IconCommand,
Button,
} from '@supabase/ui'
import Image from 'next/image'
import Link from 'next/link'
import { useTheme } from '../Providers'
import ThemeToggle from '../ThemeToggle'
const NavBar = ({ currentPage }: { currentPage: string }) => {
const [mounted, setMounted] = useState(false)
const { isDarkMode } = useTheme()
useEffect(() => {
setMounted(true)
}, [isDarkMode])
const pageLinks = [
{ text: 'Overview', active: currentPage == 'Docs', link: '/' },
{ text: 'Guides', active: currentPage == 'Guides', link: '/guides' },
{
text: 'Reference',
active: currentPage == 'Reference',
link: '/reference/javascript/supabase-client',
},
{ text: 'Discussions', active: currentPage == 'Discussions', link: '/discussions' },
]
return (
<nav className="dark:border-scale-400 dark:bg-scale-200 sticky top-0 z-10 flex h-[72px] items-center justify-between border-b bg-white p-4 backdrop-blur backdrop-filter">
<div className="flex items-center">
<button className="mr-4 block stroke-2 lg:hidden">
<IconMenu className="text-scale-1100" />
</button>
{mounted && (
<Link href="/">
<a className="flex items-center">
<Image
className="cursor-pointer"
src={isDarkMode ? `/supabase-dark.svg` : `/supabase-light.svg`}
width={200}
height={32}
alt="Supabase Logo"
/>
</a>
</Link>
)}
<ul className="ml-8 hidden space-x-8 lg:flex">
{pageLinks.map((p) => (
<li key={`${p.text}-${p.link}`}>
<Link href={p.link}>
<a className={`text-sm ${p.active ? 'text-brand-900' : 'text-scale-1100'}`}>
{p.text}
</a>
</Link>
</li>
))}
<li>
<Link href="https://app.supabase.com">
<a className={`text-scale-1100 text-sm`}>Login</a>
</Link>
</li>
</ul>
</div>
<div className="flex items-center space-x-6">
<div className="hidden items-center space-x-6 md:flex">
<Link href="https://github.com/supabase/supabase">
<a target="_blank">
<IconGitHub className="text-scale-1100 stroke-2" />
</a>
</Link>
<Link href="https://twitter.com/supabase">
<a target="_blank">
<IconTwitter className="text-scale-1100 stroke-2" />
</a>
</Link>
<ThemeToggle />
</div>
<Input
placeholder="Search"
icon={<IconSearch />}
type="search"
actions={[
<Button disabled key="icon-command" type="default" size="tiny">
<IconCommand size="tiny" />
</Button>,
<Button disabled key="icon-letter" type="default" size="tiny">
K
</Button>,
]}
/>
</div>
</nav>
)
}
export default NavBar
-58
View File
@@ -1,58 +0,0 @@
import { Menu } from '@supabase/ui'
import Link from 'next/link'
import { useRouter } from 'next/router'
const SideBar = ({ menuItems }: { menuItems: any }) => {
const { asPath } = useRouter()
return (
<div className="dark:bg-scale-200 dark:border-scale-400 thin-scrollbar sidebar-width sticky top-0 flex h-screen overflow-y-scroll border-r py-4">
<Menu className="w-full">
<div>
{Object.keys(menuItems).map((key) => {
return (
<div key={key} className="mb-4">
<Menu.Group title={key} />
{menuItems[key].map(
(item: { link: string; text: string; sections: Array<any> }) => (
<span key={item.link}>
{Array.isArray(item.sections) ? (
<>
<Menu.Group title={item.text} />
{item.sections.map((section) => (
<Link href={section.link} key={`${item.text}-${section.text}`}>
<a>
<Menu.Item active={asPath == section.link}>
{section.text}
</Menu.Item>
</a>
</Link>
))}
</>
) : (
<Link href={item.link}>
<a>
<Menu.Item active={asPath === item.link}>
<div
className={
asPath === item.link ? 'text-brand-900' : 'text-scale-1000'
}
>
{item.text}
</div>
</Menu.Item>
</a>
</Link>
)}
</span>
)
)}
</div>
)
})}
</div>
</Menu>
</div>
)
}
export default SideBar
@@ -1,807 +0,0 @@
{
"Docs": {
"Overview": [
{ "text": "Introduction", "link": "/" },
{ "text": "Architecture", "link": "/architecture" },
{ "text": "Database", "link": "/guides/database" },
{ "text": "Auth", "link": "/guides/auth" },
{ "text": "Storage", "link": "/guides/storage" },
{ "text": "APIs", "link": "/guides/apis" },
{ "text": "Examples and Resources", "link": "/guides/examples" }
],
"Tutorials": [
{ "text": "Quickstart: Angular", "link": "/guides/with-angular" },
{ "text": "Quickstart: Next.js", "link": "/guides/with-nextjs" },
{ "text": "Quickstart: Nuxt 3", "link": "/guides/with-nuxt-3" },
{ "text": "Quickstart: Flutter", "link": "/guides/with-flutter" },
{ "text": "Quickstart: React", "link": "/guides/with-react" },
{ "text": "Quickstart: RedwoodJS", "link": "/guides/with-redwoodjs" },
{ "text": "Quickstart: Svelte", "link": "/guides/with-svelte" },
{ "text": "Quickstart: Vue 3", "link": "/guides/with-vue-3" }
],
"See Also": [
{ "text": "FAQs", "link": "/faqs" },
{ "text": "Going into Prod Checklist", "link": "/going-into-prod" },
{ "text": "Contributing", "link": "/handbook/contributing" },
{ "text": "SupaSquad", "link": "/handbook/supasquad" },
{ "text": "Terms of Service", "link": "/company/terms" },
{ "text": "Privacy Policy", "link": "/company/privacy" },
{ "text": "Acceptable Use Policy", "link": "/company/aup" }
]
},
"Guides": {
"Guides": [
{ "text": "Overview", "link": "/guides" },
{ "text": "Local Development", "link": "/guides/local-development" }
],
"Database": [
{ "text": "Introduction", "link": "/guides/database/introduction" },
{ "text": "Tables", "link": "/guides/database/tables" },
{ "text": "Functions", "link": "/guides/database/functions" },
{ "text": "Full Text Search", "link": "/guides/database/full-text-search" },
{
"text": "Extensions",
"sections": [
{
"text": "Overview",
"link": "/guides/database/extensions"
},
{
"text": "plv8: Javascript Language",
"link": "/guides/database/extensions/plv8"
},
{
"text": "http: RESTful Client",
"link": "/guides/database/extensions/http"
},
{
"text": "uuid-ossp: Unique Identifiers",
"link": "/guides/database/extensions/uuid-ossp"
}
]
},
{
"text": "Connecting to Postgres",
"sections": [
{
"text": "Overview",
"link": "/guides/database/connecting/connecting-to-postgres"
},
{
"text": "Direct Connections",
"link": "/guides/database/connecting/direct-connections"
},
{
"text": "Connection Pooling",
"link": "/guides/database/connecting/connection-pooling"
}
]
},
{
"text": "Configuration",
"sections": [
{
"text": "Timeouts",
"link": "/guides/database/timeouts"
},
{
"text": "Direct Connections",
"link": "/guides/database/replication"
},
{
"text": "Passwords",
"link": "/guides/database/managing-passwords"
},
{
"text": "Timezones",
"link": "/guides/database/managing-timezones"
}
]
}
],
"Auth": [
{
"text": "Introduction",
"link": "/guides/auth/intro"
},
{
"text": "Authentication",
"sections": [
{ "text": "Login With Email", "link": "/guides/auth/auth-email" },
{ "text": "Login With Magic Link", "link": "/guides/auth/auth-magic-link" },
{ "text": "Login With Apple", "link": "/guides/auth/auth-apple" },
{ "text": "Login With Bitbucket", "link": "/guides/auth/auth-bitbucket" },
{ "text": "Login With Discord", "link": "/guides/auth/auth-discord" },
{ "text": "Login With Facebook", "link": "/guides/auth/auth-facebook" },
{ "text": "Login With GitHub", "link": "/guides/auth/auth-gitHub" },
{ "text": "Login With GitLab", "link": "/guides/auth/auth-gitLab" },
{ "text": "Login With Google", "link": "/guides/auth/auth-google" },
{ "text": "Login With Slack", "link": "/guides/auth/auth-slack" },
{ "text": "Login With Spotify", "link": "/guides/auth/auth-spotify" },
{ "text": "Login With Twitter", "link": "/guides/auth/auth-twitter" },
{ "text": "Login With Twitch", "link": "/guides/auth/auth-twitch" },
{ "text": "Phone Auth With Twilio", "link": "/guides/auth/auth-twilio" },
{ "text": "Phone Auth With MessageBird", "link": "/guides/auth/auth-messageBird" }
]
},
{
"text": "Authorization",
"sections": [
{ "text": "Row Level Security", "link": "/guides/auth/row-level-security" },
{ "text": "Managing User Data", "link": "/guides/auth/managing-user-data" }
]
},
{
"text": "Deep Dive",
"link": [
{ "text": "Part One: JWTs", "link": "/guides/auth-deep-dive/auth-deep-dive-jwts" },
{
"text": "Part Two: Row Level Security",
"link": "/guides/auth-deep-dive/auth-row-level-security"
},
{ "text": "Part Three: Policies", "link": "/guides/auth-deep-dive/auth-policies" },
{ "text": "Part Four: Gotrue", "link": "/guides/auth-deep-dive/auth-gotrue" },
{ "text": "Part Five: Google Oauth", "link": "/guides/auth-deep-dive/auth-google-auth" }
]
}
],
"Integrations": [
{
"text": "Auth0",
"link": "/guides/integrations/auth0"
},
{
"text": "Draftbit",
"link": "/guides/integrations/draftbit"
},
{
"text": "Prisma",
"link": "/guides/integrations/prisma"
},
{
"text": "Vercel",
"link": "/guides/integrations/vercel"
}
],
"Self Hosting": [
{ "text": "Overview", "link": "/guides/hosting/overview" },
{ "text": "Supabase Platform", "link": "/guides/hosting/platform" },
{ "text": "With Docker", "link": "/guides/hosting/docker" }
]
},
"Reference": {
"JAVASCRIPT": [
{
"text": "Getting Started",
"sections": [
{ "text": "Getting Started", "link": "/reference/javascript/index" },
{ "text": "Installing", "link": "/reference/javascript/installing" },
{ "text": "Initializing", "link": "/reference/javascript/initializing" },
{ "text": "Generating Types", "link": "/reference/javascript/generating-types" }
]
},
{
"text": "Auth",
"sections": [
{ "text": "signUp()", "link": "/reference/javascript/auth-signup" },
{ "text": "signIn()", "link": "/reference/javascript/auth-signin" },
{ "text": "signOut()", "link": "/reference/javascript/auth-signout" },
{ "text": "session()", "link": "/reference/javascript/auth-session" },
{ "text": "user()", "link": "/reference/javascript/auth-user" },
{ "text": "update()", "link": "/reference/javascript/auth-update" },
{ "text": "setAuth()", "link": "/reference/javascript/auth-setauth" },
{ "text": "onAuthStateChange()", "link": "/reference/javascript/auth-onauthstatechange" },
{ "text": "getUser()", "link": "/reference/javascript/auth-api-getuser" },
{ "text": "Reset Password(Email)", "link": "/reference/javascript/reset-password-email" }
]
},
{
"text": "Auth (Server Only)",
"sections": [
{ "text": "createUser()", "link": "/reference/javascript/auth-api-createuser" },
{ "text": "deleteUser()", "link": "/reference/javascript/auth-api-deleteuser" },
{ "text": "generateLink()", "link": "/reference/javascript/auth-api-generatelink" },
{
"text": "inviteUserByEmail()",
"link": "/reference/javascript/auth-api-inviteuserbyemail"
},
{ "text": "sendMobileOTP()", "link": "/reference/javascript/auth-api-sendmobileotp" },
{
"text": "resetPasswordForEmail()",
"link": "/reference/javascript/auth-api-resetpasswordforemail"
}
]
},
{
"text": "Database",
"sections": [
{
"text": "Fetch data: select()",
"link": "/reference/javascript/select"
},
{
"text": "Create data: insert()",
"link": "/reference/javascript/insert"
},
{
"text": "Modify data: update()",
"link": "/reference/javascript/update"
},
{
"text": "Upsert data: upsert()",
"link": "/reference/javascript/upsert"
},
{
"text": "Delete data: delete()",
"link": "/reference/javascript/delete"
},
{
"text": "Postgres functions: rpc()",
"link": "/reference/javascript/rpc"
}
]
},
{
"text": "Realtime",
"sections": [
{
"text": "on().subscribe()",
"link": "/reference/javascript/subscribe"
},
{
"text": "removeSubscription()",
"link": "/reference/javascript/removesubscription"
},
{
"text": "removeAllSubscriptions()",
"link": "/reference/javascript/removeallsubscriptions"
},
{
"text": "getSubscriptions()",
"link": "/reference/javascript/getsubscriptions"
}
]
},
{
"text": "Storage",
"sections": [
{
"text": "createBucket()",
"link": "/reference/javascript/storage-createbucket"
},
{
"text": "getBucket()",
"link": "/reference/javascript/storage-getbucket"
},
{
"text": "listBuckets()",
"link": "/reference/javascript/storage-listbuckets"
},
{
"text": "updateBucket()",
"link": "/reference/javascript/storage-updatebucket"
},
{
"text": "deleteBucket()",
"link": "/reference/javascript/storage-deletebucket"
},
{
"text": "emptyBucket()",
"link": "/reference/javascript/storage-emptybucket"
},
{
"text": "from.upload()",
"link": "/reference/javascript/storage-from-upload"
},
{
"text": "from.download()",
"link": "/reference/javascript/storage-from-download"
},
{
"text": "from.list()",
"link": "/reference/javascript/storage-from-list"
},
{
"text": "from.update()",
"link": "/reference/javascript/storage-from-update"
},
{
"text": "from.move()",
"link": "/reference/javascript/storage-from-move"
},
{
"text": "from.remove()",
"link": "/reference/javascript/storage-from-remove"
},
{
"text": "from.createSignedUrl()",
"link": "/reference/javascript/storage-from-createsignedurl"
},
{
"text": "from.getPublicUrl()",
"link": "/reference/javascript/storage-from-getpublicurl"
}
]
},
{
"text": "Modifiers",
"sections": [
{
"text": "Using Modifiers",
"link": "/reference/javascript/using-modifiers"
},
{
"text": "limit()",
"link": "/reference/javascript/limit"
},
{
"text": "order()",
"link": "/reference/javascript/order"
},
{
"text": "range()",
"link": "/reference/javascript/range"
},
{
"text": "single()",
"link": "/reference/javascript/single"
},
{
"text": "maybeSingle()",
"link": "/reference/javascript/maybesingle"
}
]
},
{
"text": "Filters",
"sections": [
{
"text": "Using Filters",
"link": "/reference/javascript/using-filters"
},
{
"text": "or()",
"link": "/reference/javascript/or"
},
{
"text": "not()",
"link": "/reference/javascript/not"
},
{
"text": "match()",
"link": "/reference/javascript/match"
},
{
"text": "eq()",
"link": "/reference/javascript/eq"
},
{
"text": "neq()",
"link": "/reference/javascript/neq"
},
{
"text": "gt()",
"link": "/reference/javascript/gt"
},
{
"text": "gte()",
"link": "/reference/javascript/gte"
},
{
"text": "lt()",
"link": "/reference/javascript/lt"
},
{
"text": "lte()",
"link": "/reference/javascript/lte"
},
{
"text": "like()",
"link": "/reference/javascript/like"
},
{
"text": "ilike()",
"link": "/reference/javascript/ilike"
},
{
"text": "is()",
"link": "/reference/javascript/is"
},
{
"text": "in()",
"link": "/reference/javascript/in"
},
{
"text": "contains()",
"link": "/reference/javascript/contains"
},
{
"text": "containedBy()",
"link": "/reference/javascript/containedby"
},
{
"text": "rangeLt()",
"link": "/reference/javascript/rangelt"
},
{
"text": "rangeGt()",
"link": "/reference/javascript/rangegt"
},
{
"text": "rangeGte()",
"link": "/reference/javascript/rangegte"
},
{
"text": "rangeLte()",
"link": "/reference/javascript/rangelte"
},
{
"text": "rangeAdjacent()",
"link": "/reference/javascript/rangeadjacent"
},
{
"text": "overlaps()",
"link": "/reference/javascript/overlaps"
},
{
"text": "textSearch()",
"link": "/reference/javascript/textsearch"
},
{
"text": "filter()",
"link": "/reference/javascript/filter"
}
]
}
],
"DART": [
{
"text": "Getting Started",
"sections": [
{ "text": "Installing", "link": "/reference/dart/installing" },
{ "text": "Initializing", "link": "/reference/dart/initializing" }
]
},
{
"text": "Auth",
"sections": [
{ "text": "signUp()", "link": "/reference/dart/auth-signup" },
{ "text": "signIn()", "link": "/reference/dart/auth-signin" },
{ "text": "signOut()", "link": "/reference/dart/auth-signout" },
{ "text": "session()", "link": "/reference/dart/auth-session" },
{ "text": "user()", "link": "/reference/dart/auth-user" },
{ "text": "update()", "link": "/reference/dart/auth-update" },
{ "text": "setAuth()", "link": "/reference/dart/auth-setauth" },
{ "text": "onAuthStateChange()", "link": "/reference/dart/auth-onauthsatechange" },
{ "text": "Reset Password(Email)", "link": "/reference/dart/reset-password-email" }
]
},
{
"text": "Database",
"sections": [
{
"text": "Fetch data: select()",
"link": "/reference/dart/select"
},
{
"text": "Create data: insert()",
"link": "/reference/dart/insert"
},
{
"text": "Modify data: update()",
"link": "/reference/dart/update"
},
{
"text": "Upsert data: upsert()",
"link": "/reference/dart/upsert"
},
{
"text": "Delete data: delete()",
"link": "/reference/dart/delete"
},
{
"text": "Postgres functions: rpc()",
"link": "/reference/dart/rpc"
}
]
},
{
"text": "Realtime",
"sections": [
{
"text": "on().subscribe()",
"link": "/reference/dart/subscribe"
},
{
"text": "removeSubscription()",
"link": "/reference/dart/removesubscription"
},
{
"text": "getSubscriptions()",
"link": "/reference/dart/getsubscriptions"
}
]
},
{
"text": "Storage",
"sections": [
{
"text": "createBucket()",
"link": "/reference/dart/storage-createbucket"
},
{
"text": "getBucket()",
"link": "/reference/dart/storage-getbucket"
},
{
"text": "listBuckets()",
"link": "/reference/dart/storage-listbuckets"
},
{
"text": "updateBucket()",
"link": "/reference/dart/storage-updatebucket"
},
{
"text": "deleteBucket()",
"link": "/reference/dart/storage-deletebucket"
},
{
"text": "emptyBucket()",
"link": "/reference/dart/storage-emptybucket"
},
{
"text": "from.upload()",
"link": "/reference/dart/storage-from-upload"
},
{
"text": "from.download()",
"link": "/reference/dart/storage-from-download"
},
{
"text": "from.list()",
"link": "/reference/dart/storage-from-list"
},
{
"text": "from.update()",
"link": "/reference/dart/storage-from-update"
},
{
"text": "from.move()",
"link": "/reference/dart/storage-from-move"
},
{
"text": "from.remove()",
"link": "/reference/dart/storage-from-remove"
},
{
"text": "from.createSignedUrl()",
"link": "/reference/dart/storage-from-createsignedurl"
},
{
"text": "from.getPublicUrl()",
"link": "/reference/dart/storage-from-getpublicurl"
}
]
},
{
"text": "Modifiers",
"sections": [
{
"text": "Using Modifiers",
"link": "/reference/dart/using-modifiers"
},
{
"text": "limit()",
"link": "/reference/dart/limit"
},
{
"text": "order()",
"link": "/reference/dart/order"
},
{
"text": "range()",
"link": "/reference/dart/range"
},
{
"text": "single()",
"link": "/reference/dart/single"
},
{
"text": "maybeSingle()",
"link": "/reference/dart/maybesingle"
}
]
},
{
"text": "Filters",
"sections": [
{
"text": "Using Filters",
"link": "/reference/dart/using-filters"
},
{
"text": "or()",
"link": "/reference/dart/or"
},
{
"text": "not()",
"link": "/reference/dart/not"
},
{
"text": "match()",
"link": "/reference/dart/match"
},
{
"text": "eq()",
"link": "/reference/dart/eq"
},
{
"text": "neq()",
"link": "/reference/dart/neq"
},
{
"text": "gt()",
"link": "/reference/dart/gt"
},
{
"text": "gte()",
"link": "/reference/dart/gte"
},
{
"text": "lt()",
"link": "/reference/dart/lt"
},
{
"text": "lte()",
"link": "/reference/dart/lte"
},
{
"text": "like()",
"link": "/reference/dart/like"
},
{
"text": "ilike()",
"link": "/reference/dart/ilike"
},
{
"text": "is_()",
"link": "/reference/dart/is_"
},
{
"text": "in_()",
"link": "/reference/dart/in_"
},
{
"text": "contains()",
"link": "/reference/dart/contains"
},
{
"text": "containedBy()",
"link": "/reference/dart/containedby"
},
{
"text": "rangeLt()",
"link": "/reference/dart/rangelt"
},
{
"text": "rangeGt()",
"link": "/reference/dart/rangegt"
},
{
"text": "rangeGte()",
"link": "/reference/dart/rangegte"
},
{
"text": "rangeLte()",
"link": "/reference/dart/rangelte"
},
{
"text": "rangeAdjacent()",
"link": "/reference/dart/rangeadjacent"
},
{
"text": "overlaps()",
"link": "/reference/dart/overlaps"
},
{
"text": "textSearch()",
"link": "/reference/dart/textsearch"
},
{
"text": "filter()",
"link": "/reference/dart/filter"
}
]
}
],
"CLI": [
{
"text": "About",
"sections": [{ "text": "About", "link": "/reference/cli/about" }]
},
{
"text": "Command reference",
"sections": [
{
"text": "supabase help",
"link": "/reference/cli/supabase-help"
},
{
"text": "supabase init",
"link": "/reference/cli/supabase-init"
},
{
"text": "supabase start",
"link": "/reference/cli/supabase-start"
},
{
"text": "supabase stop",
"link": "/reference/cli/supabase-stop"
},
{
"text": "supabase eject",
"link": "/reference/cli/supabase-eject"
},
{
"text": "supabase db branch list",
"link": "/reference/cli/supabase-db-branch-list"
},
{
"text": "supabase db branch create",
"link": "/reference/cli/supabase-db-branch-create"
},
{
"text": "supabase db branch delete",
"link": "/reference/cli/supabase-db-branch-delete"
},
{
"text": "supabase db switch",
"link": "/reference/cli/supabase-db-switch"
},
{
"text": "supabase db changes",
"link": "/reference/cli/supabase-db-changes"
},
{
"text": "supabase db commit",
"link": "/reference/cli/supabase-db-commit"
},
{
"text": "supabase db reset",
"link": "/reference/cli/supabase-db-reset"
},
{
"text": "supabase db remote set",
"link": "/reference/cli/supabase-db-remote-set"
},
{
"text": "supabase db remote commit",
"link": "/reference/cli/supabase-db-remote-commit"
},
{
"text": "supabase db push",
"link": "/reference/cli/supabase-db-push"
},
{
"text": "supabase migration new",
"link": "/reference/cli/supabase-migration-new"
}
]
},
{
"text": "Config reference",
"sections": [
{
"text": "Config reference",
"link": "/reference/cli/config-reference"
}
]
}
]
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import Link from 'next/link'
import { IconArrowLeft, IconArrowRight } from '@supabase/ui'
import { IconArrowLeft, IconArrowRight } from 'ui'
const pagination = ({ currentPage, totalCount }: { currentPage: number; totalCount: number }) => {
// TODO: not sure if this is the most efficient way to do this. may need to refactor.
+12
View File
@@ -0,0 +1,12 @@
const Nav = [
{
label: 'Auth',
items: [
{ name: 'Auth Server', url: '/reference/auth', items: [] },
{ name: 'Configuration', url: '/reference/auth/config', items: [] },
{ name: 'Release Notes', url: '/reference/auth/release-notes', items: [] },
],
},
]
export default Nav
+13
View File
@@ -0,0 +1,13 @@
const Nav = [
{
label: 'Storage',
items: [
{ name: 'Storage Server', url: '/reference/storage', items: [] },
{ name: 'Usage', url: '/reference/storage/usage', items: [] },
{ name: 'Configuration', url: '/reference/storage/config', items: [] },
{ name: 'Release Notes', url: '/reference/storage/release-notes', items: [] },
],
},
]
export default Nav
+12
View File
@@ -0,0 +1,12 @@
const Nav = [
{
label: 'API',
items: [
{ name: 'Supabase API', url: '/reference/api', items: [] },
{ name: 'Usage', url: '/reference/api/usage', items: [] },
{ name: 'Release Notes', url: '/reference/api/release-notes', items: [] },
],
},
]
export default Nav
+13
View File
@@ -0,0 +1,13 @@
const Nav = [
{
label: 'CLI',
items: [
{ name: 'Supabase CLI', url: '/reference/cli', items: [] },
{ name: 'Usage', url: '/reference/cli/usage', items: [] },
{ name: 'Configuration', url: '/reference/cli/config', items: [] },
{ name: 'Release Notes', url: '/reference/cli/release-notes', items: [] },
],
},
]
export default Nav
+132
View File
@@ -0,0 +1,132 @@
const Nav = [
{
label: 'Getting Started',
items: [
{ name: 'Supabase Dart Library', url: '/reference/dart/v0', items: [] },
{ name: 'Installing', url: '/reference/dart/v0/installing', items: [] },
{ name: 'Initializing', url: '/reference/dart/v0/initializing', items: [] },
],
},
{
label: 'Auth',
items: [
{ name: 'signUp()', url: '/reference/dart/v0/auth-signup', items: [] },
{ name: 'signIn()', url: '/reference/dart/v0/auth-signin', items: [] },
{
name: 'signInWithProvider()',
url: '/reference/dart/v0/auth-signinwithprovider',
items: [],
},
{ name: 'signOut()', url: '/reference/dart/v0/auth-signout', items: [] },
{ name: 'session()', url: '/reference/dart/v0/auth-session', items: [] },
{ name: 'user()', url: '/reference/dart/v0/auth-user', items: [] },
{ name: 'update()', url: '/reference/dart/v0/auth-update', items: [] },
{
name: 'onAuthStateChange()',
url: '/reference/dart/v0/auth-onauthstatechanged',
items: [],
},
{
name: 'Reset Password (Email)',
url: '/reference/dart/v0/reset-password-email',
items: [],
},
],
},
{
label: 'Functions',
items: [{ name: 'invoke()', url: '/reference/dart/v0/invoke', items: [] }],
},
{
label: 'Database',
items: [
{ name: 'Fetch data: select()', url: '/reference/dart/v0/select', items: [] },
{ name: 'Create data: insert()', url: '/reference/dart/v0/insert', items: [] },
{ name: 'Modify data: update()', url: '/reference/dart/v0/update', items: [] },
{ name: 'Upsert data: upsert()', url: '/reference/dart/v0/upsert', items: [] },
{ name: 'Delete data: delete()', url: '/reference/dart/v0/delete', items: [] },
{ name: 'Stored Procedures: rpc()', url: '/reference/dart/v0/rpc', items: [] },
],
},
{
label: 'Realtime',
items: [
{ name: 'stream', url: '/reference/dart/v0/stream', items: [] },
{ name: 'on().subscribe()', url: '/reference/dart/v0/subscribe', items: [] },
{
name: 'removeSubscription()',
url: '/reference/dart/v0/removesubscription',
items: [],
},
{ name: 'getSubscriptions()', url: '/reference/dart/v0/getsubscriptions', items: [] },
],
},
{
label: 'Storage',
items: [
{ name: 'createBucket()', url: '/reference/dart/v0/storage-createbucket', items: [] },
{ name: 'getBucket()', url: '/reference/dart/v0/storage-getbucket', items: [] },
{ name: 'listBuckets()', url: '/reference/dart/v0/storage-listbuckets', items: [] },
{ name: 'updateBucket()', url: '/reference/dart/v0/storage-updatebucket', items: [] },
{ name: 'deleteBucket()', url: '/reference/dart/v0/storage-deletebucket', items: [] },
{ name: 'emptyBucket()', url: '/reference/dart/v0/storage-emptybucket', items: [] },
{ name: 'from.upload()', url: '/reference/dart/v0/storage-from-upload', items: [] },
{ name: 'from.download()', url: '/reference/dart/v0/storage-from-download', items: [] },
{ name: 'from.list()', url: '/reference/dart/v0/storage-from-list', items: [] },
{ name: 'from.update()', url: '/reference/dart/v0/storage-from-update', items: [] },
{ name: 'from.move()', url: '/reference/dart/v0/storage-from-move', items: [] },
{ name: 'from.remove()', url: '/reference/dart/v0/storage-from-remove', items: [] },
{
name: 'from.createSignedUrl()',
url: '/reference/dart/v0/storage-from-createsignedurl',
items: [],
},
{
name: 'from.getPublicUrl()',
url: '/reference/dart/v0/storage-from-getpublicurl',
items: [],
},
],
},
{
label: 'Filters',
items: [
{ name: 'Using Filters', url: '/reference/dart/v0/using-filters', items: [] },
{ name: 'eq()', url: '/reference/dart/v0/eq', items: [] },
{ name: 'neq()', url: '/reference/dart/v0/neq', items: [] },
{ name: 'gt()', url: '/reference/dart/v0/gt', items: [] },
{ name: 'gte()', url: '/reference/dart/v0/gte', items: [] },
{ name: 'lt()', url: '/reference/dart/v0/lt', items: [] },
{ name: 'lte()', url: '/reference/dart/v0/lte', items: [] },
{ name: 'like()', url: '/reference/dart/v0/like', items: [] },
{ name: 'ilike()', url: '/reference/dart/v0/ilike', items: [] },
{ name: 'is_()', url: '/reference/dart/v0/is_', items: [] },
{ name: 'in_()', url: '/reference/dart/v0/in_', items: [] },
{ name: 'contains()', url: '/reference/dart/v0/contains', items: [] },
{ name: 'containedBy()', url: '/reference/dart/v0/containedby', items: [] },
{ name: 'rangeGt()', url: '/reference/dart/v0/rangegt', items: [] },
{ name: 'rangeGte()', url: '/reference/dart/v0/rangegte', items: [] },
{ name: 'rangeLt()', url: '/reference/dart/v0/rangelt', items: [] },
{ name: 'rangeLte()', url: '/reference/dart/v0/rangelte', items: [] },
{ name: 'rangeAdjacent()', url: '/reference/dart/v0/rangeadjacent', items: [] },
{ name: 'overlaps()', url: '/reference/dart/v0/overlaps', items: [] },
{ name: 'textSearch()', url: '/reference/dart/v0/textsearch', items: [] },
{ name: 'match()', url: '/reference/dart/v0/match', items: [] },
{ name: 'not()', url: '/reference/dart/v0/not', items: [] },
{ name: 'or()', url: '/reference/dart/v0/or', items: [] },
{ name: 'filter()', url: '/reference/dart/v0/filter', items: [] },
],
},
{
label: 'Modifiers',
items: [
{ name: 'Using Modifiers', url: '/reference/dart/v0/using-modifiers', items: [] },
{ name: 'order()', url: '/reference/dart/v0/order', items: [] },
{ name: 'limit()', url: '/reference/dart/v0/limit', items: [] },
{ name: 'range()', url: '/reference/dart/v0/range', items: [] },
{ name: 'single()', url: '/reference/dart/v0/single', items: [] },
],
},
]
export default Nav
+130
View File
@@ -0,0 +1,130 @@
const Nav = [
{
label: 'Getting Started',
items: [
{ name: 'Supabase Flutter Library', url: '/reference/dart', items: [] },
{ name: 'Installing', url: '/reference/dart/installing', items: [] },
{ name: 'Initializing', url: '/reference/dart/initializing', items: [] },
{ name: 'Upgrading to supabase-flutter v1', url: '/reference/dart/upgrade-guide', items: [] },
],
},
{
label: 'Auth',
items: [
{ name: 'signUp()', url: '/reference/dart/auth-signup', items: [] },
{
name: 'signInWithPassword()',
url: '/reference/dart/auth-signinwithpassword',
items: [],
},
{ name: 'signInWithOtp()', url: '/reference/dart/auth-signinwithotp', items: [] },
{ name: 'signInWithOAuth()', url: '/reference/dart/auth-signinwithoauth', items: [] },
{ name: 'signOut()', url: '/reference/dart/auth-signout', items: [] },
{ name: 'verifyOtp()', url: '/reference/dart/auth-verifyotp', items: [] },
{ name: 'currentSession', url: '/reference/dart/auth-currentsession', items: [] },
{ name: 'currentUser', url: '/reference/dart/auth-currentuser', items: [] },
{ name: 'updateUser()', url: '/reference/dart/auth-updateuser', items: [] },
{ name: 'setSession()', url: '/reference/dart/auth-setSession', items: [] },
{
name: 'resetPasswordForEmail()',
url: '/reference/dart/auth-resetpasswordforemail',
items: [],
},
],
},
{
label: 'Functions',
items: [{ name: 'invoke()', url: '/reference/dart/invoke', items: [] }],
},
{
label: 'Database',
items: [
{ name: 'Fetch data: select()', url: '/reference/dart/select', items: [] },
{ name: 'Create data: insert()', url: '/reference/dart/insert', items: [] },
{ name: 'Modify data: update()', url: '/reference/dart/update', items: [] },
{ name: 'Upsert data: upsert()', url: '/reference/dart/upsert', items: [] },
{ name: 'Delete data: delete()', url: '/reference/dart/delete', items: [] },
{ name: 'Stored Procedures: rpc()', url: '/reference/dart/rpc', items: [] },
{
name: 'Filters',
url: undefined,
items: [
{ name: 'Using Filters', url: '/reference/dart/using-filters', items: [] },
{ name: 'eq()', url: '/reference/dart/eq', items: [] },
{ name: 'neq()', url: '/reference/dart/neq', items: [] },
{ name: 'gt()', url: '/reference/dart/gt', items: [] },
{ name: 'gte()', url: '/reference/dart/gte', items: [] },
{ name: 'lt()', url: '/reference/dart/lt', items: [] },
{ name: 'lte()', url: '/reference/dart/lte', items: [] },
{ name: 'like()', url: '/reference/dart/like', items: [] },
{ name: 'ilike()', url: '/reference/dart/ilike', items: [] },
{ name: 'is_()', url: '/reference/dart/is_', items: [] },
{ name: 'in_()', url: '/reference/dart/in_', items: [] },
{ name: 'contains()', url: '/reference/dart/contains', items: [] },
{ name: 'containedBy()', url: '/reference/dart/containedby', items: [] },
{ name: 'rangeGt()', url: '/reference/dart/rangegt', items: [] },
{ name: 'rangeGte()', url: '/reference/dart/rangegte', items: [] },
{ name: 'rangeLt()', url: '/reference/dart/rangelt', items: [] },
{ name: 'rangeLte()', url: '/reference/dart/rangelte', items: [] },
{ name: 'rangeAdjacent()', url: '/reference/dart/rangeadjacent', items: [] },
{ name: 'overlaps()', url: '/reference/dart/overlaps', items: [] },
{ name: 'textSearch()', url: '/reference/dart/textsearch', items: [] },
{ name: 'match()', url: '/reference/dart/match', items: [] },
{ name: 'not()', url: '/reference/dart/not', items: [] },
{ name: 'or()', url: '/reference/dart/or', items: [] },
{ name: 'filter()', url: '/reference/dart/filter', items: [] },
],
},
{
name: 'Modifiers',
url: undefined,
items: [
{ name: 'Using Modifiers', url: '/reference/dart/using-modifiers', items: [] },
{ name: 'order()', url: '/reference/dart/order', items: [] },
{ name: 'limit()', url: '/reference/dart/limit', items: [] },
{ name: 'range()', url: '/reference/dart/range', items: [] },
{ name: 'single()', url: '/reference/dart/single', items: [] },
],
},
],
},
{
label: 'Realtime',
items: [
{ name: 'stream()', url: '/reference/dart/stream', items: [] },
{ name: 'on().subscribe()', url: '/reference/dart/subscribe', items: [] },
{ name: 'removeChannel()', url: '/reference/dart/removechannel', items: [] },
{ name: 'removeAllChannels()', url: '/reference/dart/removeallchannels', items: [] },
{ name: 'getChannels()', url: '/reference/dart/getchannels', items: [] },
],
},
{
label: 'Storage',
items: [
{ name: 'createBucket()', url: '/reference/dart/storage-createbucket', items: [] },
{ name: 'getBucket()', url: '/reference/dart/storage-getbucket', items: [] },
{ name: 'listBuckets()', url: '/reference/dart/storage-listbuckets', items: [] },
{ name: 'updateBucket()', url: '/reference/dart/storage-updatebucket', items: [] },
{ name: 'deleteBucket()', url: '/reference/dart/storage-deletebucket', items: [] },
{ name: 'emptyBucket()', url: '/reference/dart/storage-emptybucket', items: [] },
{ name: 'from.upload()', url: '/reference/dart/storage-from-upload', items: [] },
{ name: 'from.download()', url: '/reference/dart/storage-from-download', items: [] },
{ name: 'from.list()', url: '/reference/dart/storage-from-list', items: [] },
{ name: 'from.update()', url: '/reference/dart/storage-from-update', items: [] },
{ name: 'from.move()', url: '/reference/dart/storage-from-move', items: [] },
{ name: 'from.remove()', url: '/reference/dart/storage-from-remove', items: [] },
{
name: 'from.createSignedUrl()',
url: '/reference/dart/storage-from-createsignedurl',
items: [],
},
{
name: 'from.getPublicUrl()',
url: '/reference/dart/storage-from-getpublicurl',
items: [],
},
],
},
]
export default Nav
+169
View File
@@ -0,0 +1,169 @@
const Nav = [
{
label: 'Getting Started',
items: [
{ name: 'Supabase Javascript Library', url: '/reference/javascript/v1', items: [] },
{ name: 'Installing', url: '/reference/javascript/v1/installing', items: [] },
{ name: 'Initializing', url: '/reference/javascript/v1/initializing', items: [] },
{ name: 'Generating Types', url: '/reference/javascript/v1/generating-types', items: [] },
],
},
{
label: 'Auth',
items: [
{ name: 'signUp()', url: '/reference/javascript/v1/auth-signup', items: [] },
{ name: 'signIn()', url: '/reference/javascript/v1/auth-signin', items: [] },
{ name: 'signOut()', url: '/reference/javascript/v1/auth-signout', items: [] },
{ name: 'session()', url: '/reference/javascript/v1/auth-session', items: [] },
{ name: 'user()', url: '/reference/javascript/v1/auth-user', items: [] },
{ name: 'update()', url: '/reference/javascript/v1/auth-update', items: [] },
{ name: 'setAuth()', url: '/reference/javascript/v1/auth-setauth', items: [] },
{
name: 'onAuthStateChange()',
url: '/reference/javascript/v1/auth-onauthstatechanged',
items: [],
},
{ name: 'getUser()', url: '/reference/javascript/v1/auth-api-getuser', items: [] },
{
name: 'resetPasswordForEmail()',
url: '/reference/javascript/v1/auth-api-resetpasswordforemail',
items: [],
},
],
},
{
label: 'Auth (Server Only)',
items: [
{ name: 'listUsers()', url: '/reference/javascript/v1/auth-api-listusers', items: [] },
{ name: 'createUser()', url: '/reference/javascript/v1/auth-api-createuser', items: [] },
{ name: 'deleteUser()', url: '/reference/javascript/v1/auth-api-deleteuser', items: [] },
{
name: 'generateLink()',
url: '/reference/javascript/v1/auth-api-generatelink',
items: [],
},
{
name: 'inviteUserByEmail()',
url: '/reference/javascript/v1/auth-api-inviteuserbyemail',
items: [],
},
{
name: 'sendMobileOTP()',
url: '/reference/javascript/v1/auth-api-sendmobileotp',
items: [],
},
{
name: 'updateUserById()',
url: '/reference/javascript/v1/auth-api-updateuserbyid',
items: [],
},
],
},
{
label: 'Functions',
items: [{ name: 'invoke()', url: '/reference/javascript/v1/invoke', items: [] }],
},
{
label: 'Database',
items: [
{ name: 'Fetch data: select()', url: '/reference/javascript/v1/select', items: [] },
{ name: 'Create data: insert()', url: '/reference/javascript/v1/insert', items: [] },
{ name: 'Modify data: update()', url: '/reference/javascript/v1/update', items: [] },
{ name: 'Upsert data: upsert()', url: '/reference/javascript/v1/upsert', items: [] },
{ name: 'Delete data: delete()', url: '/reference/javascript/v1/delete', items: [] },
{ name: 'Postgres functions: rpc()', url: '/reference/javascript/v1/rpc', items: [] },
],
},
{
label: 'Realtime',
items: [
{ name: 'on().subscribe()', url: '/reference/javascript/v1/subscribe', items: [] },
{
name: 'removeSubscription()',
url: '/reference/javascript/v1/removesubscription',
items: [],
},
{
name: 'removeAllSubscriptions()',
url: '/reference/javascript/v1/removeallsubscriptions',
items: [],
},
{ name: 'getSubscriptions()', url: '/reference/javascript/v1/getsubscriptions', items: [] },
],
},
{
label: 'Storage',
items: [
{ name: 'createBucket()', url: '/reference/javascript/v1/storage-createbucket', items: [] },
{ name: 'getBucket()', url: '/reference/javascript/v1/storage-getbucket', items: [] },
{ name: 'listBuckets()', url: '/reference/javascript/v1/storage-listbuckets', items: [] },
{ name: 'updateBucket()', url: '/reference/javascript/v1/storage-updatebucket', items: [] },
{ name: 'deleteBucket()', url: '/reference/javascript/v1/storage-deletebucket', items: [] },
{ name: 'emptyBucket()', url: '/reference/javascript/v1/storage-emptybucket', items: [] },
{ name: 'from.upload()', url: '/reference/javascript/v1/storage-from-upload', items: [] },
{ name: 'from.download()', url: '/reference/javascript/v1/storage-from-download', items: [] },
{ name: 'from.list()', url: '/reference/javascript/v1/storage-from-list', items: [] },
{ name: 'from.update()', url: '/reference/javascript/v1/storage-from-update', items: [] },
{ name: 'from.move()', url: '/reference/javascript/v1/storage-from-move', items: [] },
{ name: 'from.copy()', url: '/reference/javascript/v1/storage-from-copy', items: [] },
{ name: 'from.remove()', url: '/reference/javascript/v1/storage-from-remove', items: [] },
{
name: 'from.createSignedUrl()',
url: '/reference/javascript/v1/storage-from-createsignedurl',
items: [],
},
{
name: 'from.createSignedUrls()',
url: '/reference/javascript/v1/storage-from-createsignedurls',
items: [],
},
{
name: 'from.getPublicUrl()',
url: '/reference/javascript/v1/storage-from-getpublicurl',
items: [],
},
],
},
{
label: 'Filters',
items: [
{ name: 'Using Filters', url: '/reference/javascript/v1/using-filters', items: [] },
{ name: 'eq()', url: '/reference/javascript/v1/eq', items: [] },
{ name: 'neq()', url: '/reference/javascript/v1/neq', items: [] },
{ name: 'gt()', url: '/reference/javascript/v1/gt', items: [] },
{ name: 'gte()', url: '/reference/javascript/v1/gte', items: [] },
{ name: 'lt()', url: '/reference/javascript/v1/lt', items: [] },
{ name: 'lte()', url: '/reference/javascript/v1/lte', items: [] },
{ name: 'like()', url: '/reference/javascript/v1/like', items: [] },
{ name: 'ilike()', url: '/reference/javascript/v1/ilike', items: [] },
{ name: 'is()', url: '/reference/javascript/v1/is', items: [] },
{ name: 'in()', url: '/reference/javascript/v1/in', items: [] },
{ name: 'contains()', url: '/reference/javascript/v1/contains', items: [] },
{ name: 'containedBy()', url: '/reference/javascript/v1/containedby', items: [] },
{ name: 'rangeGt()', url: '/reference/javascript/v1/rangegt', items: [] },
{ name: 'rangeGte()', url: '/reference/javascript/v1/rangegte', items: [] },
{ name: 'rangeLt()', url: '/reference/javascript/v1/rangelt', items: [] },
{ name: 'rangeLte()', url: '/reference/javascript/v1/rangelte', items: [] },
{ name: 'rangeAdjacent()', url: '/reference/javascript/v1/rangeadjacent', items: [] },
{ name: 'overlaps()', url: '/reference/javascript/v1/overlaps', items: [] },
{ name: 'textSearch()', url: '/reference/javascript/v1/textsearch', items: [] },
{ name: 'match()', url: '/reference/javascript/v1/match', items: [] },
{ name: 'not()', url: '/reference/javascript/v1/not', items: [] },
{ name: 'or()', url: '/reference/javascript/v1/or', items: [] },
{ name: 'filter()', url: '/reference/javascript/v1/filter', items: [] },
],
},
{
label: 'Modifiers',
items: [
{ name: 'Using Modifiers', url: '/reference/javascript/v1/using-modifiers', items: [] },
{ name: 'order()', url: '/reference/javascript/v1/order', items: [] },
{ name: 'limit()', url: '/reference/javascript/v1/limit', items: [] },
{ name: 'range()', url: '/reference/javascript/v1/range', items: [] },
{ name: 'single()', url: '/reference/javascript/v1/single', items: [] },
{ name: 'maybeSingle()', url: '/reference/javascript/v1/maybesingle', items: [] },
],
},
]
export default Nav
+166
View File
@@ -0,0 +1,166 @@
const Nav = [
{
label: 'Getting Started',
items: [
{ name: 'Supabase Javascript Library', url: '/reference/javascript', items: [] },
{ name: 'Installing', url: '/reference/javascript/installing', items: [] },
{ name: 'Initializing', url: '/reference/javascript/initializing', items: [] },
{ name: 'Typescript Support', url: '/reference/javascript/typescript-support', items: [] },
{ name: 'Release Notes', url: '/reference/javascript/release-notes', items: [] },
{
name: 'Upgrading to supabase-js v2',
url: '/reference/javascript/upgrade-guide',
items: [],
},
],
},
{
label: 'Auth',
items: [
{ name: 'signUp()', url: '/reference/javascript/auth-signup', items: [] },
{
name: 'signInWithPassword()',
url: '/reference/javascript/auth-signinwithpassword',
items: [],
},
{ name: 'signInWithOtp()', url: '/reference/javascript/auth-signinwithotp', items: [] },
{ name: 'signInWithOAuth()', url: '/reference/javascript/auth-signinwithoauth', items: [] },
{ name: 'signOut()', url: '/reference/javascript/auth-signout', items: [] },
{ name: 'verifyOtp()', url: '/reference/javascript/auth-verifyotp', items: [] },
{ name: 'getSession()', url: '/reference/javascript/auth-getsession', items: [] },
{ name: 'getUser()', url: '/reference/javascript/auth-getuser', items: [] },
{ name: 'updateUser()', url: '/reference/javascript/auth-updateuser', items: [] },
{ name: 'setSession()', url: '/reference/javascript/auth-setSession', items: [] },
{
name: 'resetPasswordForEmail()',
url: '/reference/javascript/auth-resetpasswordforemail',
items: [],
},
],
},
{
label: 'Auth (Server Only)',
items: [
{ name: 'Overview', url: '/reference/javascript/supabase-auth-admin-api', items: [] },
{ name: 'listUsers()', url: '/reference/javascript/auth-admin-listusers', items: [] },
{ name: 'createUser()', url: '/reference/javascript/auth-admin-createuser', items: [] },
{ name: 'deleteUser()', url: '/reference/javascript/auth-admin-deleteuser', items: [] },
{ name: 'generateLink()', url: '/reference/javascript/auth-admin-generatelink', items: [] },
{
name: 'inviteUserByEmail()',
url: '/reference/javascript/auth-admin-inviteuserbyemail',
items: [],
},
{ name: 'getUserById()', url: '/reference/javascript/auth-admin-getuserbyid', items: [] },
{
name: 'updateUserById()',
url: '/reference/javascript/auth-admin-updateuserbyid',
items: [],
},
],
},
{
label: 'Database',
items: [
{ name: 'Fetch data: select()', url: '/reference/javascript/select', items: [] },
{ name: 'Create data: insert()', url: '/reference/javascript/insert', items: [] },
{ name: 'Modify data: update()', url: '/reference/javascript/update', items: [] },
{ name: 'Upsert data: upsert()', url: '/reference/javascript/upsert', items: [] },
{ name: 'Delete data: delete()', url: '/reference/javascript/delete', items: [] },
{ name: 'Postgres functions: rpc()', url: '/reference/javascript/rpc', items: [] },
{
name: 'Filters',
url: undefined,
items: [
{ name: 'Using Filters', url: '/reference/javascript/using-filters', items: [] },
{ name: 'eq()', url: '/reference/javascript/eq', items: [] },
{ name: 'neq()', url: '/reference/javascript/neq', items: [] },
{ name: 'gt()', url: '/reference/javascript/gt', items: [] },
{ name: 'gte()', url: '/reference/javascript/gte', items: [] },
{ name: 'lt()', url: '/reference/javascript/lt', items: [] },
{ name: 'lte()', url: '/reference/javascript/lte', items: [] },
{ name: 'like()', url: '/reference/javascript/like', items: [] },
{ name: 'ilike()', url: '/reference/javascript/ilike', items: [] },
{ name: 'is()', url: '/reference/javascript/is', items: [] },
{ name: 'in()', url: '/reference/javascript/in', items: [] },
{ name: 'contains()', url: '/reference/javascript/contains', items: [] },
{ name: 'containedBy()', url: '/reference/javascript/containedby', items: [] },
{ name: 'rangeGt()', url: '/reference/javascript/rangegt', items: [] },
{ name: 'rangeGte()', url: '/reference/javascript/rangegte', items: [] },
{ name: 'rangeLt()', url: '/reference/javascript/rangelt', items: [] },
{ name: 'rangeLte()', url: '/reference/javascript/rangelte', items: [] },
{ name: 'rangeAdjacent()', url: '/reference/javascript/rangeadjacent', items: [] },
{ name: 'overlaps()', url: '/reference/javascript/overlaps', items: [] },
{ name: 'textSearch()', url: '/reference/javascript/textsearch', items: [] },
{ name: 'match()', url: '/reference/javascript/match', items: [] },
{ name: 'not()', url: '/reference/javascript/not', items: [] },
{ name: 'or()', url: '/reference/javascript/or', items: [] },
{ name: 'filter()', url: '/reference/javascript/filter', items: [] },
],
},
{
name: 'Modifiers',
url: undefined,
items: [
{ name: 'Using Modifiers', url: '/reference/javascript/using-modifiers', items: [] },
{ name: 'select()', url: '/reference/javascript/db-modifiers-select', items: [] },
{ name: 'order()', url: '/reference/javascript/order', items: [] },
{ name: 'limit()', url: '/reference/javascript/limit', items: [] },
{ name: 'range()', url: '/reference/javascript/range', items: [] },
{ name: 'abortSignal()', url: '/reference/javascript/db-abortsignal', items: [] },
{ name: 'single()', url: '/reference/javascript/single', items: [] },
{ name: 'maybeSingle()', url: '/reference/javascript/maybesingle', items: [] },
{ name: 'csv()', url: '/reference/javascript/db-csv', items: [] },
],
},
],
},
{
label: 'Functions',
items: [{ name: 'invoke()', url: '/reference/javascript/invoke', items: [] }],
},
{
label: 'Realtime',
items: [
{ name: 'on().subscribe()', url: '/reference/javascript/subscribe', items: [] },
{ name: 'removeChannel()', url: '/reference/javascript/removechannel', items: [] },
{ name: 'removeAllChannels()', url: '/reference/javascript/removeallchannels', items: [] },
{ name: 'getChannels()', url: '/reference/javascript/getchannels', items: [] },
],
},
{
label: 'Storage',
items: [
{ name: 'createBucket()', url: '/reference/javascript/storage-createbucket', items: [] },
{ name: 'getBucket()', url: '/reference/javascript/storage-getbucket', items: [] },
{ name: 'listBuckets()', url: '/reference/javascript/storage-listbuckets', items: [] },
{ name: 'updateBucket()', url: '/reference/javascript/storage-updatebucket', items: [] },
{ name: 'deleteBucket()', url: '/reference/javascript/storage-deletebucket', items: [] },
{ name: 'emptyBucket()', url: '/reference/javascript/storage-emptybucket', items: [] },
{ name: 'from.upload()', url: '/reference/javascript/storage-from-upload', items: [] },
{ name: 'from.download()', url: '/reference/javascript/storage-from-download', items: [] },
{ name: 'from.list()', url: '/reference/javascript/storage-from-list', items: [] },
{ name: 'from.update()', url: '/reference/javascript/storage-from-update', items: [] },
{ name: 'from.move()', url: '/reference/javascript/storage-from-move', items: [] },
{ name: 'from.copy()', url: '/reference/javascript/storage-from-copy', items: [] },
{ name: 'from.remove()', url: '/reference/javascript/storage-from-remove', items: [] },
{
name: 'from.createSignedUrl()',
url: '/reference/javascript/storage-from-createsignedurl',
items: [],
},
{
name: 'from.createSignedUrls()',
url: '/reference/javascript/storage-from-createsignedurls',
items: [],
},
{
name: 'from.getPublicUrl()',
url: '/reference/javascript/storage-from-getpublicurl',
items: [],
},
],
},
]
export default Nav
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: 'Architecture'
description: 'Supabase Architecture'
title: 'Architecture',
description: 'Supabase Architecture',
---
# Architecture
+6 -2
View File
@@ -1,11 +1,12 @@
---
title: 'FAQs'
description: 'Supabase frequently asked questions'
title: 'FAQs',
description: 'Supabase frequently asked questions',
---
# FAQs
### Have you built `[Firebase feature]` yet?
We're building as fast as we can! And we are even adding a few things that Firebase doesn't have, as we go. Here are the features we have built:
- A dashboard/UI for spinning up and managing your database in less than one minute.
@@ -19,10 +20,13 @@ We're building as fast as we can! And we are even adding a few things that Fireb
We started Supabase because we love the functionality of Firebase, but we personally experienced the scaling issues that many others experienced. We chose Postgres because it's well-trusted and it has phenomenal scalability. Our goal is to make Postgres as easy to use as Firebase, so that you no longer have to choose between usability and scalability. Also, we're sure that once you start using Postgres, you'll love it more than any other database.
### How do I host Supabase?
Supabase is an amalgamation of five open source tools (and growing). Some of these tools are made by Supabase (like our [Realtime Server](https://github.com/supabase/realtime)), some we support indirectly (like [PostgREST](http://postgrest.org/en/v7.0.0/)), and some are third-party tools (like [Kong](https://github.com/Kong/kong)). All of the tools we use in Supabase are MIT, Apache 2.0, or PostgreSQL licensed. You can use the docker-compose script [here](https://github.com/supabase/supabase/tree/master/docker) to build Supabase on your own environment, and find detailed instructions [here](https://supabase.com/docs/guides/hosting/overview).
### Do you support `[some other database]`?
At the moment, we only support PostgreSQL. It's unlikely we'll ever move away from Postgres; however, you can [vote on a new database](https://github.com/supabase/supabase/issues/6) if you want us to start development.
### Do you have a library for `[some other language]`?
We currently have a JavaScript library. You can [vote on a new client library](https://github.com/supabase/supabase/issues/5) for your favorite language.
+19 -19
View File
@@ -1,7 +1,7 @@
---
id: going-into-prod
title: Going into Prod Checklist
description: 'Things to do before making your app publicly available'
id: 'going-into-prod',
title: 'Going into Prod Checklist',
description: 'Things to do before making your app publicly available',
---
# Going into Prod Checklist
@@ -15,39 +15,39 @@ After developing your project, and deciding it's time to Go Live With Real Users
## Security
- Ensure RLS is enabled
- Tables that do not have RLS enabled with reasonable policies allow any client to access and modify their data. This is unlikely to be what you want in the majority of cases.
- [Learn more about RLS](/docs/guides/auth/row-level-security)
- Tables that do not have RLS enabled with reasonable policies allow any client to access and modify their data. This is unlikely to be what you want in the majority of cases.
- [Learn more about RLS](/docs/guides/auth/row-level-security)
- Ensure replication is disabled for tables containing sensitive data:
- Today, Realtime does not respect RLS policies and any client with your anon key can listen to changes on tables where replication is enabled.
- Go to the Database > Replication page in the Supabase Dashboard to manage these settings
- We are launching [RLS for realtime](https://github.com/supabase/walrus) soon, but in the meantime you should only use it for tables containing public data (scoreboards, blog posts, etc.)
- Today, Realtime does not respect RLS policies and any client with your anon key can listen to changes on tables where replication is enabled.
- Go to the Database > Replication page in the Supabase Dashboard to manage these settings
- We are launching [RLS for realtime](https://github.com/supabase/walrus) soon, but in the meantime you should only use it for tables containing public data (scoreboards, blog posts, etc.)
- Enable 2FA on Github
- Since your Github account gives you administrative rights to your Supabase project, you should protect it with a strong password and 2FA using a U2F key or a TOTP app.
- Since your Github account gives you administrative rights to your Supabase project, you should protect it with a strong password and 2FA using a U2F key or a TOTP app.
- Ensure email confirmations are enabled in the Auth > Settings page
- Use a custom SMTP server for auth emails so that your users can see that the mails are coming from a trusted domain (preferably the same domain that your app is hosted on). (grab SMTP credentials from any major email provider such as SendGrid, AWS SES, etc.)
- Think hard about how *you* would abuse your service as an attacker, and mitigate
- Think hard about how _you_ would abuse your service as an attacker, and mitigate
- Review these [common cybersecurity threats](https://auth0.com/docs/security/prevent-threats)
## Performance
- Ensure that you have suitable indices to cater to your common query patterns
- [learn more about indexes in postgres](https://www.enterprisedb.com/postgres-tutorials/overview-postgresql-indexes)
- pg_stat_statements can help you [identify hot or slow queries](https://www.virtual-dba.com/blog/postgresql-performance-identifying-hot-and-slow-queries/)
- [learn more about indexes in postgres](https://www.enterprisedb.com/postgres-tutorials/overview-postgresql-indexes)
- pg_stat_statements can help you [identify hot or slow queries](https://www.virtual-dba.com/blog/postgresql-performance-identifying-hot-and-slow-queries/)
- Perform load testing (preferably on a staging env)
- tools like [k6](https://k6.io/) can simulate traffic from many different users
- tools like [k6](https://k6.io/) can simulate traffic from many different users
- If you find you require more resources, contact support@supabase.io to upgrade to PAYG for bigger servers
## Availability
- Use your own SMTP credentials so that you have full control over the deliverability of your transactional auth emails (see Auth > Settings)
- you can grab SMTP credentials from any major email provider such as SendGrid, AWS SES, etc.
- the default rate limit for auth emails provided by Supabase is 30 new users per hour, if doing a major public announcement you will likely require more than this
- you can grab SMTP credentials from any major email provider such as SendGrid, AWS SES, etc.
- the default rate limit for auth emails provided by Supabase is 30 new users per hour, if doing a major public announcement you will likely require more than this
- If your application is on the free tier and is **not** expected to be queried at least once every 7 days, then it may be paused by Supabase to save on server resources
- you can restore paused projects from the Supabase dashboard
- upgrade to Pro to guarantee that your project will not be paused for inactivity
- you can restore paused projects from the Supabase dashboard
- upgrade to Pro to guarantee that your project will not be paused for inactivity
- Database backups are not available for download on the free tier
- You can set up your own backup systems using tools like [pg_dump](https://www.postgresqltutorial.com/postgresql-backup-database/) or [wal-g](https://github.com/wal-g/wal-g)
- Nightly backups for Pro tier projects are available on the Supabase dashboard for up to 7 days
- You can set up your own backup systems using tools like [pg_dump](https://www.postgresqltutorial.com/postgresql-backup-database/) or [wal-g](https://github.com/wal-g/wal-g)
- Nightly backups for Pro tier projects are available on the Supabase dashboard for up to 7 days
- upgrading to the Supabase Pro Tier will give you access to email support on support@supabase.io
This checklist is always growing so be sure to check back frequently, and also feel free to suggest additions and amendments by making a PR on [Github](https://github.com/supabase/supabase).
@@ -0,0 +1,66 @@
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.md'
## Project set up
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
and then creating a "schema" inside the database.
### Create a project
1. Go to [app.supabase.com](https://app.supabase.com).
1. Click on "New Project".
1. Enter your project details.
1. Wait for the new database to launch.
### Set up the database schema
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
or you can just copy/paste the SQL from below and run it yourself.
<Tabs
groupId="language"
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard.
2. Click **User Management Starter**.
3. Click **Run**.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/sql-user-management-starter.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
</TabItem>
<TabItem value="sql">
<UserManagementSQLTemplate />
</TabItem>
</Tabs>
### Get the API Keys
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
We just need to get the URL and `anon` key from the API settings.
1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard.
2. Click **API** in the sidebar.
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
Loaded 100 of 514 files, more files were not shown because too many files have changed in this diff. Show more