Merge pull request #10797 from supabase/master

Prod deploy dashboard
This commit is contained in:
Joshen Lim authored and GitHub committed 2022-12-08 18:23:36 +08:00
commit 52aa28bf8b
41 files changed
+18141 -15002

No files matched your search

+5 -7
View File
@@ -35,8 +35,6 @@ We are in the process of migrating this repository to monorepo, using [Turborepo
Eventually, all the apps will be run using [Turborepo](https://turborepo.org/docs), which will significantly improve the developer workflow.
If you are working on the ([docs site](https://supabase.com/docs)), please refer to this [developers guide](https://github.com/supabase/supabase/tree/master/apps/reference/DEVELOPERS.md).
### Fork the repository
To contribute code to [Supabase](https://supabase.com), you must fork the [Supabase Repository](https://github.com/supabase/supabase).
@@ -71,11 +69,11 @@ To contribute code to [Supabase](https://supabase.com), you must fork the [Supab
Then visit, and edit, any of the following sites:
| Site | Directory | Scope name | Description | Local development server |
| ---------------------------------------------- | -------------- | ---------- | ------------------------------------ | ------------------------ |
| [supabase.com](https://supabase.com) | `/apps/www` | www | The main website | http://localhost:3000 |
| [app.supabase.com](https://app.supabase.com) | `/studio` | studio | Studio dashboard | http://localhost:8082 |
| [supabase.com/docs](https://supabase.com/docs) | `/apps/docs` | docs | Guides and Reference (Next.js based) | http://localhost:3001/docs |
| Site | Directory | Scope name | Description | Local development server |
| ---------------------------------------------- | ------------ | ---------- | ------------------------------------ | -------------------------- |
| [supabase.com](https://supabase.com) | `/apps/www` | www | The main website | http://localhost:3000 |
| [app.supabase.com](https://app.supabase.com) | `/studio` | studio | Studio dashboard | http://localhost:8082 |
| [supabase.com/docs](https://supabase.com/docs) | `/apps/docs` | docs | Guides and Reference (Next.js based) | http://localhost:3001/docs |
#### Running sites individually
@@ -245,7 +245,9 @@ export const menuItems: NavMenu = {
label: 'Storage',
items: [
{ name: 'Overview', url: '/guides/storage', items: [] },
{ name: 'CDN', url: '/guides/storage-cdn', items: [] },
{ name: 'Quickstart', url: '/guides/storage/quickstart', items: [] },
{ name: 'Access Control', url: '/guides/storage/access-control', items: [] },
{ name: 'CDN', url: '/guides/storage/cdn', items: [] },
],
},
{
File diff suppressed because it is too large. Load diff
@@ -295,6 +295,7 @@ If you try to submit a form with the action `?/createPost` without a valid sessi
import type { Actions } from './$types'
import { invalid, redirect } from '@sveltejs/kit'
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
import { AuthApiError } from '@supabase/supabase-js'
export const actions: Actions = {
signin: async (event) => {
-336
View File
@@ -34,342 +34,6 @@ keep all video files in a "video" bucket, and profile pictures in an "avatar" bu
></iframe>
</div>
## Getting started
This is a quick guide that shows the basic functionality of Supabase Storage. Find a full
[example application in GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management),
which you can deploy yourself.
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fsupabase%2Fsupabase%2Ftree%2Fmaster%2Fexamples%2Fuser-management%2Fnextjs-ts-user-management&project-name=supabase-user-management&repository-name=supabase-user-management&demo-title=Supabase%20User%20Management&demo-description=An%20example%20web%20app%20using%20Supabase%20and%20Next.js&demo-url=https%3A%2F%2Fsupabase-nextjs-ts-user-management.vercel.app&demo-image=https%3A%2F%2Fi.imgur.com%2FZ3HkQqe.png&integration-ids=oac_jUduyjQgOyzev1fjrW83NYOv&external-id=nextjs-user-management)
<Admonition type="note">
File, Folder, and Bucket names **must follow** [AWS object key naming guidelines](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html) and avoid use of any other characters.
</Admonition>
### Create a bucket
You can create a bucket using the Supabase Dashboard.
Since the storage is interoperable with your Postgres database, you can also use SQL or our
client libraries. Here we create a bucket called "avatars":
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Click **New Bucket** and enter a name for the bucket.
3. Click **Create Bucket**.
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Use Postgres to create a bucket.
insert into storage.buckets (id, name)
values ('avatars', 'avatars');
```
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
// Use the JS library to create a bucket.
const { data, error } = await supabase.storage.createBucket('avatars')
```
[Reference.](/docs/reference/javascript/storage-createbucket)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
final storageResponse = await supabase
.storage
.createBucket('avatars');
}
```
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</Tabs>
### Upload a file
You can upload a file from the Dashboard, or within a browser using our JS libraries.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Select the bucket you want to upload the file to.
3. Click **Upload File**.
4. Select the file you want to upload.
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
const avatarFile = event.target.files[0]
const { data, error } = await supabase.storage
.from('avatars')
.upload('public/avatar1.png', avatarFile)
```
[Reference.](/docs/reference/javascript/storage-from-upload)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
// Create file `example.txt` and upload it in `public` bucket
final file = File('example.txt');
file.writeAsStringSync('File content');
final storageResponse = await supabase
.storage
.from('public')
.upload('example.txt', file);
}
```
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</Tabs>
### Download a file
You can download a file from the Dashboard, or within a browser using our JS libraries.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Select the bucket that contains the file.
3. Select the file that you want to download.
4. Click **Download**.
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
// Use the JS library to download a file.
const { data, error } = await supabase.storage.from('avatars').download('public/avatar1.png')
```
[Reference.](/docs/reference/javascript/storage-from-download)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
final storageResponse = await supabase
.storage
.from('public')
.download('example.txt');
}
```
[Reference.](/docs/reference/dart/storage-from-download)
</TabPanel>
</Tabs>
### Add security rules
To restrict access to your files you can use either the Dashboard or SQL.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Click **Policies** in the sidebar.
3. Click **Add Policies** in the `OBJECTS` table to add policies for Files. You can also create policies for Buckets.
4. Choose whether you want the policy to apply to downloads (SELECT), uploads (INSERT), updates (UPDATE), or deletes (DELETE).
5. Give your policy a unique name.
6. Write the policy using SQL.
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Use SQL to create a policy.
create policy "Public Access"
on storage.objects for select
using ( bucket_id = 'public' );
```
</TabPanel>
</Tabs>
## Public and Private Buckets
Storage buckets are private by default.
For private buckets, you can access objects via the [download](/docs/reference/javascript/storage-from-download) method. This corresponds to `/object/auth/` API endpoint.
Alternatively, you can create a publicly shareable URL with an expiry date using the [createSignedUrl](/docs/reference/javascript/storage-from-createsignedurl) method
which calls the `/object/sign/` API.
For public buckets, you can access the assets directly without a token or an Authorisation header. The [getPublicUrl](/docs/reference/javascript/storage-from-getpublicurl)
helper method returns the full public URL for an asset. This calls the `/object/public/` API endpoint internally. While no authorization is required for accessing objects in a public bucket, proper [access control](#access-control) is required for other operations like uploading, deleting objects from public buckets as well.
Public buckets also tend to have [better performance](/docs/guides/storage-cdn#public-vs-private-buckets).
<details>
<summary>Advanced: reverse proxy</summary>
The URLs returned are proxied through the API Proxy. They are prefixed by <code>/storage/v1</code>.
For example, on the hosted Platform they will be
<code>https://[project_ref].supabase.co/storage/v1/object/public/[id]</code>
You can access the storage API directly with the same endpoint. See the <a href="https://supabase.github.io/storage-api">API docs</a> for a full list of operations available.
</details>
---
## Access control
Supabase Storage is integrated with your [Postgres Database](/docs/guides/database).
This means that you can use the same [Row Level Security Policies](/docs/guides/auth#policies)
for managing access to your files. Supabase Storage stores metadata in the `objects` and `buckets` table in the storage schema. To allow read access to files, the RLS policy must allow users to `SELECT` the `objects` table and for uploading a new object, the RLS policy must grant users access to `INSERT` into the `objects` table and so on. The mapping between the different API calls and the database permissions required is documented in the [Reference docs](/docs/reference/javascript/storage-createbucket).
<Admonition type="note">
Access control for Storage is mapped to CRUD operations on the `buckets` and `objects` table via RLS policies.
</Admonition>
<div className="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/4ERX__Y908k"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
## Helpers
Supabase Storage provides SQL helper functions which you can use in your database queries and
policies.
---
#### `storage.filename()`
Returns the name of a file.
```sql
select storage.filename(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`'avatar.png'`
---
#### `storage.foldername()`
Returns an array path, with all of the subfolders that a file belongs to.
```sql
select storage.foldername(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`[ 'public', 'subfolder' ]`
---
#### `storage.extension()`
Returns the extension of a file.
```sql
select storage.extension(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`'png'`
---
## Policy examples
Here are some examples of storage policies.
### Allow public access to a bucket
```sql
-- 1. Allow public access to any files in the "public" bucket
create policy "Public Access"
on storage.objects for select
using ( bucket_id = 'public' );
```
### Allow logged-in access to a bucket
```sql
-- 1. Allow logged-in access to any files in the "restricted" bucket
create policy "Restricted Access"
on storage.objects for select
using (
bucket_id = 'restricted'
and auth.role() = 'authenticated'
);
```
### Allow individual access to a file
```sql
-- 1. Allow a user to access their own files
create policy "Individual user Access"
on storage.objects for select
using ( auth.uid() = owner );
```
## See also
- Read more about Supabase Storage in the [blog post](https://supabase.com/blog/supabase-storage)
@@ -0,0 +1,137 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'storage-access-control',
title: 'Access Control',
description: 'Manage who can access your Supabase Storage files.',
}
Supabase Storage is integrated with your [Postgres Database](/docs/guides/database).
This means that you can use the same [Row Level Security Policies](/docs/guides/auth#policies)
for managing access to your files. Supabase Storage stores metadata in the `objects` and `buckets` table in the storage schema.
To allow read access to files, the RLS policy must allow users to `SELECT` the `objects` table and for uploading a new object, the RLS policy must grant users access to `INSERT` into the `objects` table and so on. The mapping between the different API calls and the database permissions required is documented in the [Reference docs](/docs/reference/javascript/storage-createbucket).
<Admonition type="note">
Access control for Storage is mapped to CRUD operations on the `buckets` and `objects` table via RLS policies.
</Admonition>
<div className="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/4ERX__Y908k"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
## Public and private buckets
Storage buckets are private by default. For private buckets, you can access objects via the [download](/docs/reference/javascript/storage-from-download) method. This corresponds to `/object/auth/` API endpoint.
Alternatively, you can create a publicly shareable URL with an expiry date using the [createSignedUrl](/docs/reference/javascript/storage-from-createsignedurl) method
which calls the `/object/sign/` API.
For public buckets, you can access the assets directly without a token or an Authorisation header. The [getPublicUrl](/docs/reference/javascript/storage-from-getpublicurl)
helper method returns the full public URL for an asset. This calls the `/object/public/` API endpoint internally. While no authorization is required for accessing objects in a public bucket, proper [access control](#access-control) is required for other operations like uploading, deleting objects from public buckets as well. Public buckets also tend to have [better performance](/docs/guides/storage-cdn#public-vs-private-buckets).
<details>
<summary>Advanced: reverse proxy</summary>
The URLs returned are proxied through the API Proxy. They are prefixed by <code>/storage/v1</code>.
For example, on the hosted Platform they will be
<code>https://[project_ref].supabase.co/storage/v1/object/public/[id]</code>
You can access the storage API directly with the same endpoint. See the <a href="https://supabase.github.io/storage-api">API docs</a> for a full list of operations available.
</details>
## Helper functions
Supabase Storage provides SQL helper functions which you can use in your database queries and
policies.
---
#### `storage.filename()`
Returns the name of a file.
```sql
select storage.filename(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`'avatar.png'`
---
#### `storage.foldername()`
Returns an array path, with all of the subfolders that a file belongs to.
```sql
select storage.foldername(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`[ 'public', 'subfolder' ]`
---
#### `storage.extension()`
Returns the extension of a file.
```sql
select storage.extension(name)
from storage.objects;
```
For example, if your file is stored in `public/subfolder/avatar.png` it would return:
`'png'`
---
## Policy examples
### Allow public access to a bucket
```sql
-- 1. Allow public access to any files in the "public" bucket
create policy "Public Access"
on storage.objects for select
using ( bucket_id = 'public' );
```
### Allow logged-in access to a bucket
```sql
-- 1. Allow logged-in access to any files in the "restricted" bucket
create policy "Restricted Access"
on storage.objects for select
using (
bucket_id = 'restricted'
and auth.role() = 'authenticated'
);
```
### Allow individual access to a file
```sql
-- 1. Allow a user to access their own files
create policy "Individual user Access"
on storage.objects for select
using ( auth.uid() = owner );
```
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -3,27 +3,19 @@ import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'storage-cdn',
title: 'Storage CDN',
description: 'How Supabase Storage caches objects with a CDN',
description: 'Learn how Supabase Storage caches objects with a CDN.',
sidebar_label: 'CDN',
}
## CDN basics
All assets uploaded to Supabase Storage are cached on a Content Delivery Network (CDN) to improve the latency for users all around the world. CDNs are a geographically distributed set of servers or **nodes** which caches content from an **origin server**. For Supabase Storage, the origin is the storage server running in the [same region as your project](https://app.supabase.com/project/_/settings/general). Aside from performance, CDNs also help with security and availability by mitigating Distributed Denial of Service and other application attacks.
All assets uploaded to storage are cached on a Content Delivery Network (CDN).
To improve the latency for users all around the world, Supabase uses a CDN. CDNs are a geographically distributed set of servers or **nodes** which caches content from an **origin server**. For Supabase Storage, the origin is the storage server running in the [same region as your project](https://app.supabase.com/project/_/settings/general).
## Example
Let’s walk through an example of how a CDN helps with performance. A new bucket is created for a Supabase project launched in Singapore. All requests to the Supabase Storage API first hit the CDN. A user from the United States requests an object and is routed to the U.S. CDN. At this point, that CDN node does not have the object in its cache and pings the origin server in Singapore. Another user, also in the United States, requests the same object and is served directly from the CDN cache in the United States instead of routing the request back to Singapore.
Aside from performance, CDNs also help with security and availability by mitigating Distributed Denial of Service and other application attacks.
## Cache duration
By default, assets are cached both in the CDN and in the user's browser for 1 hour. After this, the CDN nodes ping the storage server to see if an object has been updated.
You can modify this cache time when you are [uploading](/docs/reference/javascript/storage-from-upload) or [updating](/docs/reference/javascript/storage-from-update) an object by modifying the `cacheControl` parameter.
If you expect the object to not change at a given URL, setting a longer cache duration is preferable.
By default, assets are cached both in the CDN and in the user's browser for 1 hour. After this, the CDN nodes ping the storage server to see if an object has been updated. You can modify this cache time when you are [uploading](/docs/reference/javascript/storage-from-upload) or [updating](/docs/reference/javascript/storage-from-update) an object by modifying the `cacheControl` parameter. If you expect the object to not change at a given URL, setting a longer cache duration is preferable.
If you need to update the version of the object stored in the CDN, there are various cache-busting techniques you can use. The most common way to do this is to add a version query parameter in the URL. For example, you can use a URL like `/storage/v1/object/sign/profile-pictures/cat.jpg?token=eyJh...&version=1` in your applications and set a long cache time of 1 year. When you want to update the cat picture, you can increment the version query parameter in the URL. The CDN will treat `/storage/v1/object/sign/profile-pictures/cat.jpg?token=eyJh...&version=2` as a new object and pings the origin for the updated version.
@@ -0,0 +1,216 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'storage-quickstart',
title: 'Storage Quickstart',
description: 'Learn how to use Supabase to store and serve files.',
sidebar_label: 'Quickstart',
}
This guide shows the basic functionality of Supabase Storage. Find a full [example application on GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management) you can deploy yourself.
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fsupabase%2Fsupabase%2Ftree%2Fmaster%2Fexamples%2Fuser-management%2Fnextjs-ts-user-management&project-name=supabase-user-management&repository-name=supabase-user-management&demo-title=Supabase%20User%20Management&demo-description=An%20example%20web%20app%20using%20Supabase%20and%20Next.js&demo-url=https%3A%2F%2Fsupabase-nextjs-ts-user-management.vercel.app&demo-image=https%3A%2F%2Fi.imgur.com%2FZ3HkQqe.png&integration-ids=oac_jUduyjQgOyzev1fjrW83NYOv&external-id=nextjs-user-management)
<Admonition type="note">
File, Folder, and Bucket names **must follow** [AWS object key naming guidelines](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html) and avoid use of any other characters.
</Admonition>
## Create a bucket
You can create a bucket using the Supabase Dashboard.
Since the storage is interoperable with your Postgres database, you can also use SQL or our
client libraries. Here we create a bucket called "avatars":
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Click **New Bucket** and enter a name for the bucket.
3. Click **Create Bucket**.
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Use Postgres to create a bucket.
insert into storage.buckets (id, name)
values ('avatars', 'avatars');
```
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
// Use the JS library to create a bucket.
const { data, error } = await supabase.storage.createBucket('avatars')
```
[Reference.](/docs/reference/javascript/storage-createbucket)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
final storageResponse = await supabase
.storage
.createBucket('avatars');
}
```
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</Tabs>
## Upload a file
You can upload a file from the Dashboard, or within a browser using our JS libraries.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Select the bucket you want to upload the file to.
3. Click **Upload File**.
4. Select the file you want to upload.
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
const avatarFile = event.target.files[0]
const { data, error } = await supabase.storage
.from('avatars')
.upload('public/avatar1.png', avatarFile)
```
[Reference.](/docs/reference/javascript/storage-from-upload)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
// Create file `example.txt` and upload it in `public` bucket
final file = File('example.txt');
file.writeAsStringSync('File content');
final storageResponse = await supabase
.storage
.from('public')
.upload('example.txt', file);
}
```
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</Tabs>
## Download a file
You can download a file from the Dashboard, or within a browser using our JS libraries.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Select the bucket that contains the file.
3. Select the file that you want to download.
4. Click **Download**.
</TabPanel>
<TabPanel id="javascript" label="JavaScript">
```js
// Use the JS library to download a file.
const { data, error } = await supabase.storage.from('avatars').download('public/avatar1.png')
```
[Reference.](/docs/reference/javascript/storage-from-download)
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
void main() async {
final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');
final storageResponse = await supabase
.storage
.from('public')
.download('example.txt');
}
```
[Reference.](/docs/reference/dart/storage-from-download)
</TabPanel>
</Tabs>
## Add security rules
To restrict access to your files you can use either the Dashboard or SQL.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Storage](https://app.supabase.com/project/_/storage/buckets) page in the Dashboard.
2. Click **Policies** in the sidebar.
3. Click **Add Policies** in the `OBJECTS` table to add policies for Files. You can also create policies for Buckets.
4. Choose whether you want the policy to apply to downloads (SELECT), uploads (INSERT), updates (UPDATE), or deletes (DELETE).
5. Give your policy a unique name.
6. Write the policy using SQL.
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Use SQL to create a policy.
create policy "Public Access"
on storage.objects for select
using ( bucket_id = 'public' );
```
</TabPanel>
</Tabs>
## See also
- [Supabase Storage on GitHub](https://github.com/supabase/storage-api)
- [Swagger API documentation](https://supabase.github.io/storage-api)
- Official [JavaScript](/docs/reference/javascript/storage-createbucket) and [Dart](/docs/reference/dart/storage-createbucket) documentation
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
+1
View File
@@ -29,6 +29,7 @@ Jon M
Jonny Summers-Muir
Joshen Lim
Kang Ming Tay
Karlo Ison
Kevin Grüneberg
Lakshmipathi G
Laura C
@@ -153,7 +153,7 @@ Notice also how there is a `DEFAULT` value for the `key_id`. In a way, this give
### One Key ID per Row with Nonce Support
The default cryptographic algorithm for the above approach uses a _nonceless_ encryption algorithm called `[crypto_aead_det_xchacha20()](https://github.com/jedisct1/libsodium-xchacha20-siv)`. This algorithm has the advantage that it does not require nonce values, the disadvantage is that duplicate plaintexts will produce duplicate ciphertexts.
The default cryptographic algorithm for the above approach uses a _nonceless_ encryption algorithm called [`crypto_aead_det_xchacha20()`](https://github.com/jedisct1/libsodium-xchacha20-siv). This algorithm has the advantage that it does not require nonce values, the disadvantage is that duplicate plaintexts will produce duplicate ciphertexts.
Nonces are some extra cryptographic context that is used in many cryptographic algorithms to produce different ciphertexts, even if the plaintexts are the same. The nonce does not have to be secret, but it _does_ have to be unique. **pgsodium** comes with a useful function `pgsodium.crypto_aead_det_noncegen()` that will generate a cryptographically secure nonce for you, and in almost all cases it's best to use that function unless you know specifically what you are doing. In password hashing approaches, this is often similar to how a “salt” value is used to deduplicate password hashes.
@@ -0,0 +1,58 @@
---
title: The Supabase Content Storm
description: We worked with +30 content creators to drop a mountain of content simultaneously.
author: ramiro
image: 2022-12-06-content-storm/content-storm.jpg
thumb: 2022-12-06-content-storm/content-storm.jpg
tags:
- announcements
date: '2022-12-06'
toc_depth: 3
---
We're always trying to innovate at Supabase, so when we started planning [Launch Week 6](https://supabase.com/launch-week), we brainstormed ideas for a campaign to promote it that would involve the community. We took a bit of inspiration from things like Weezer’s YouTube takeover and came up with the concept of a Content Storm ⛈.
## What is the Content Storm?
The idea was to get many different external content creators as possible to create Supabase-related content and *publish everything on the same day*. We contacted some well known Youtubers, community members, makers building with Supabase, the SupaSquad, and generally anyone within the Supabase community. We wanted this to be an opportunity for them to build their personal brand or promote their products and startups.
## The aftermath of the storm
More than 30 creators participated in creating content in different formats and everything was published today (Tuesday 6th of December). Here is the full list of every piece of content and its author:
- [A quick look at Supabase](https://twitter.com/Rorstro/status/1600047388852293632) by Ania Kubów.
- [Live streaming: Supabase and Sveltekit](https://www.youtube.com/@JamesQQuick/streams) by James Q Quick.
- [Perform Database Migration Using Github Actions & Supabase CLI](https://www.youtube.com/watch?v=iCkdtXSeq7A) by Kunal Kushwaha.
- [Supabase Authentication & Realtime Database with Flutter](https://www.youtube.com/watch?v=UTSSYPOd5A0) by Pooja Bhaumik.
- [Why I Switched From AWS Cognito To Supabase The Week Before My Startup Launched](https://medium.com/@sleeplessfox/why-i-switched-from-aws-cognito-to-supabase-the-week-before-my-startup-launched-67fdc1eccb8c) by Danilo à Tellinghusen.
- [Supabase Crash Course For Python Developers](https://www.youtube.com/watch?v=M6cfT2pqpSc) by Patrick Loeber.
- [Hoppscotch with GraphQL](https://www.youtube.com/watch?v=HoBXQng3aK4) by Jamie Barton.
- [Supabase with TypeScript: using tRPC and Prisma to achieve end-to-end typesafety](https://noahflk.com/blog/supabase-typescript-trpc) by Noah.
- [How to Connect Browser Extensions to Supabase](https://akoskm.com/how-to-connect-browser-extensions-to-supabase) by Ákos Kőműves.
- [A Chili Cookoff with Rust, Rocket, Render, and Supabase](bradcypert.com/chili-cookoff-with-rust-rocket-render-and-supabase/) by Brad Cypert.
- [Authenticating users with Remix and Supabase](https://makerkit.dev/blog/tutorials/remix-supabase-auth) by Giancarlo Buomprisco.
- [Automatic Spotify Playlist Creation with Pipedream and Supabase](https://www.ianwootten.co.uk/2022/12/06/automatic-spotify-playlist-creation-with-pipedream-and-supabase/) by Ian Wootten.
- [Accept Payments For Your African-Based Business Using Supabase Edge Functions and Paystack](https://blog.hijabicoder.dev/accept-payments-for-your-african-based-business-using-supabase-edge-functions-and-paystack) by Fatuma Abdullahi.
- [Creating AvatarAI.me using Supabase and Cerebrium](https://blog.cerebrium.ai/creating-avatarai-me-using-supabase-and-cerebrium-1bf69440c4a7) by Cerebrium.
- [From Zero to Hero: Building Next.js Projects](https://www.youtube.com/watch?v=LR1i_8QjXyY) by Gui Bibeau.
- [Set up a monorepo with Supabase and Turborepo](https://philipp.steinroetter.com/posts/supabase-turborepo) by Philipp Steinrötter.
- [Twitter clone with Supabase](https://www.youtube.com/watch?v=JnUzV-PpopU) by Code with Guillaume.
- [How Supabase Powers Mockury](https://blog.ikirill.com/how-supabase-powers-mockury) by Kirill Inoz.
- [How to add SIGN-IN WITH APPLE using IONIC ANGULAR and SUPABASE](https://www.youtube.com/watch?v=xhzVyso-9OM) by [Simon Grimm].
- [SvelteKit + Supabase v2 Auth with Magic Links, Providers, Email + Password, & more! 🔐🔴 LIVE](https://www.youtube.com/watch?v=XuyMr4pM4B8) by Johnny Magrippis
- [How we use Supabase at Brick](https://dev.to/vinzent/how-we-use-supabase-at-brick-3a5d) by Vinzent.
- [How Kuiq is using Supabase and serving around 100 APIs](https://kuiq.io/blog/how-kuiq-is-using-supabase-and-serving-around-100-apis) by Taishi
- [How I created an interactive website with React, Chakra UI + Supabase](https://medium.com/@limjoshen/how-i-created-a-personal-website-with-react-chakra-ui-supabase-39661852746a) by Joshen Lim.
- [5 benefits of using Supabase for your SaaS](https://supastarter.dev/blog/five-benefits-of-supabase) by Jonathan Wilke.
- [Getting into the holiday spirit with Astro, React, and Supabase](https://www.aleksandra.codes/astro-supabase) by Aleksandra
- [How I build register and login page with Supabase](https://surajondev.com/2022/12/06/how-i-build-register-and-login-page-using-supabase/) by Suraj Vishwakarma.
- [What the hell is Supabase?](https://www.youtube.com/watch?v=syOnFdFC_5U) by Ayesha Sahar.
- [Comment utiliser Supabase en No-Code avec Weweb ?](https://www.youtube.com/watch?v=g2TLd8vvs0E) by Thomas Buyle.
- [How I used Supabase and n8n for my background tasks](https://mathias.rocks/blog/2022-12-06-how-I-used-supabase/) by Mathias Mitchel
- [Build An Image Gallery With Supabase Storage and React (Upload Images with Supabase)](https://www.youtube.com/watch?v=8tfdY0Sf2rA) by Coopercodes
- [Twitter thread showing how to build a web app](https://twitter.com/thisisisheanesu/status/1600257146792181766) by Isheanesu.
- [This service will run your entire app](https://www.instagram.com/reel/Cl1KWbtDGMR/) by Simon Baker (@allthecode).
It's a lot! There are tons of great resources, going through everything would take a couple of days, so we recommend bookmarking this page! If you like the content, make sure to give feedback to the author and follow them on social.
And don't miss Launch Week 6, we've been working hard to make it our best Launch Week yet 🚀. Get your tickets [here](https://supabase.com/launch-week).
@@ -0,0 +1,104 @@
---
title: Supabase Beta November 2022
description: We are preparing everything for Launch Week 6, but we still had time to ship some goodies this month!
author: ant_wilson
image: 2022-12-07-november-beta-update/monthly-update-november-2022.jpg
thumb: 2022-12-07-november-beta-update/monthly-update-november-2022.jpg
tags:
- release-notes
date: '2022-12-07'
toc_depth: 3
---
Launch Week 6 is just around the corner! We’re saving most of November’s updated as a surprise for Launch Week, but we still had time to ship some goodies this month. Read on!
## Launch Week 6 tickets
![Launch Week 6 tickets](/images/blog/2022-12-07-november-beta-update/launch-week-6-ticket.jpg)
Next week, we go all out for LW6. It’s 5 days of shipping, including major features requested by the community. You don’t want to miss a thing, so make sure to claim your free ticket (and you might win some very special SupaSwag).
[Get your ticket](https://supabase.com/launch-week)
## Remix Auth Helpers
![Remix Auth Helpers](/images/blog/2022-12-07-november-beta-update/remix-auth-helpers.jpg)
It’s here! The much-awaited Remix Auth Helpers make server-side auth even easier and with a better experience for server-side rendering. Up to date with supabase-js V2 and can be used with Typescript.
[Read the docs](https://supabase.com/docs/guides/auth/auth-helpers/remix)
## Edgy Edge Functions
![Edgy Edge Function](/images/blog/2022-12-07-november-beta-update/edgy-edge-functions.jpg)
We launched a new YouTube series, [Edgy Edge Functions](https://www.youtube.com/playlist?list=PL5S4mPUpp4OulD3olUW8Eq1IYKpUbk5Ob), where we take a deep look at a new function every week.
Plus, we published three new functions examples: [Generate OG Images](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/opengraph), [Build API servers using Oak](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/oak-server), and [Generate Screenshots using Puppeteer](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/puppeteer).
## Quick product updates
- Fixed two issues with the `supabase.auth.signOut` function: [cookies not clearing properly](https://github.com/supabase/gotrue/pull/830) and [session not removed](https://github.com/supabase/gotrue-js/pull/541).
- You can now customize magic links by providing access to the `HashedToken`. [PR](https://github.com/supabase/gotrue/pull/707)
- Now you can do redirects from your functions. [PR](https://github.com/supabase/supabase/issues/10325)
- Conda support (`conda install -c conda-forge supabase` and everything else in py)
## Content storm ⛈
![The Supabase Content Storm](/images/blog/2022-12-07-november-beta-update/content-storm.jpg)
As a prelude to Launch Week 6, we invited dozens of developers from around the world to create content in different formats and publish everything simultaneously!
[Check the full list](https://supabase.com/blog/the-supabase-content-storm)
## Fireship’s Supabase course
![Fireship’s Supabase course](/images/blog/2022-12-07-november-beta-update/fireship-supabase-course.jpg)
That guy from the [Supaship Youtube](https://www.youtube.com/@Supaship6000) channel made a Supabase Course with Fireship! Zack DeRose did an amazing job with this project-based course that builds a Reddit-inspired web app from scratch with Supabase, PostgreSQL, and React.
[Get it while it's hot](https://fireship.io/courses/supabase/).
## Made with Supabase
![Made with Supabase](/images/blog/2022-12-07-november-beta-update/madewithsupabase.jpg)
[postedbyAI](https://postedby.ai/) | Allows users to create personalized postcards using advanced AI technology. Built with Vercel, OpenAI, and Supabase.
Discover other great projects: [Made with Supabase](https://www.madewithsupabase.com/).
## Extended Community Highlights
![Community](/images/blog/2022-june/community.jpg)
- Supabase in 100 Seconds, by Fireship. [Video](https://www.youtube.com/watch)
- NextAuth Supabase Adapter. [Docs](https://next-auth.js.org/adapters/supabase)
- Flutter Authentication and Authorization with RLS. [Tutorial](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
- The pros and cons of using PostgREST. [Podcast](https://postgres.fm/episodes/postgrest)
- Querying Supabase from the edge with Netlify and PolyScale. [Tutorial](https://www.netlify.com/blog/querying-supabase-from-the-edge-with-polyscale/)
- JWT Authentication with Supabase and Zuplo for your API. [Blog](https://zuplo.com/blog/2022/11/15/api-authentication-with-supabase-jwt/) and [Video](https://www.youtube.com/watch?v=UEeSZkV7o_Y&feature=youtu.be)
- Shipping a public API backed by Supabase. [Blog](https://zuplo.com/blog/2022/11/18/shipping-a-public-api-backed-by-supabase) and [Video](https://www.youtube.com/watch?v=GJSkbxMnWxE)
- A Guide to testing on Supabase using pgTAP. [Guide](https://usebasejump.com/blog/testing-on-supabase-with-pgtap)
- [Using Bytebase to manage the database development lifecycle for Supabase databases](https://www.bytebase.com/docs/how-to/integrations/supabase)
- The Best Backend as a Service for your React App. [Article](https://www.freecodecamp.org/news/best-backend-service-react/)
- All You Need to Know About Serverless Functions and the Edge. [Article](https://dev.to/nefejames/all-you-need-to-know-about-serverless-functions-and-the-edge-2bl2)
- #1 Hack for Building JavaScript Portfolio Projects. [Video](https://www.youtube.com/watch?v=3K9VUT7H5sw)
- Livestreaming - Job Board App w/ SvelteKit, Supabase, & Prisma. [Youtube Playlist](https://www.youtube.com/playlist?list=PLq30BP0TIcqU8SlzDK2wX4IaXamQ26kpr)
- How to connect to and insert data into Supabase with Pipedream. [Article](https://pipedream.com/blog/how-to-connect-to-and-insert-data-into-supabase-with-pipedream/) and [Video](https://www.youtube.com/watch?v=l9B8F1n3duk)
- Google Sign-In using Supabase and React Native (Expo). [Tutorial](https://dev.to/fedorish/google-sign-in-using-supabase-and-react-native-expo-14jf)
- Fast and Intuitive analytics for Supabase with DB Zaps. [Video](https://www.youtube.com/watch?v=QlIlqm9eG3w)
- ReactJS + Supabase Fullstack CRUD Application Development. [Youtube Playlist](https://youtube.com/playlist?list=PLl6EcvA_AoxEFqwT_rNs1uZnnf7LSEoji)
- How to connect a ESP8266 to a Streamlit App using Supabase database. [Video](https://www.youtube.com/watch?v=wI209WK3-VM)
## Meme Zone
This month’s meme comes courtesy of Fireship. [Follow us on Twitter](https://twitter.com/supabase) for more.
![Supabase meme November 2022](/images/blog/2022-12-07-november-beta-update/november-beta-update-meme.png)
See you next month!
+3 -3
View File
@@ -30,7 +30,7 @@ const data: CommunityItem[] = [
},
{
title: 'GitHub',
stat: '40,000+',
stat: '42,000+',
statLabel: 'GitHub stars',
img: 'github.png',
invertImgDarkMode: true,
@@ -42,7 +42,7 @@ const data: CommunityItem[] = [
},
{
title: 'Twitter',
stat: '44,000+',
stat: '50,000+',
statLabel: 'Followers',
img: 'twitter.png',
detail: () => (
@@ -53,7 +53,7 @@ const data: CommunityItem[] = [
},
{
title: 'Discord',
stat: '8,000+',
stat: '10,000+',
statLabel: 'SupaTroopers',
img: 'discord.png',
detail: () => (
+7
View File
@@ -229,5 +229,12 @@
"position": "Postgres Engineer",
"author_url": "https://github.com/pashkinelfe",
"author_image_url": "https://avatars.githubusercontent.com/u/63344111?v=4"
},
{
"author_id": "ramiro",
"author": "Ramiro Nunez Dosio",
"position": "Growth Marketer",
"author_url": "https://twitter.com/ramiro__nd",
"author_image_url": "https://avatars.githubusercontent.com/u/20600542?v=4"
}
]
+3 -10
View File
@@ -30,20 +30,13 @@ export default function mdxComponents(type?: 'blog' | 'lp' | undefined) {
img: (props: any) => {
if (props.className !== ignoreClass) {
return (
<div
className={[
'next-image--dynamic-fill',
type === 'blog' && 'to-scale-400 from-scale-500 rounded-lg border bg-gradient-to-r',
].join(' ')}
>
<span className={['next-image--dynamic-fill'].join(' ')}>
<Image
{...props}
className={['next-image--dynamic-fill', type === 'blog' && 'rounded-md border'].join(
' '
)}
className={[type === 'blog' ? 'rounded-md border' : ''].join(' ')}
layout="fill"
/>
</div>
</span>
)
}
return <img {...props} />
+6 -1
View File
@@ -7,7 +7,7 @@ module.exports = [
{
permanent: true,
source: '/docs/guides/storage-caching',
destination: '/docs/guides/storage-cdn',
destination: '/docs/guides/storage/cdn',
},
{
permanent: true,
@@ -1560,6 +1560,11 @@ module.exports = [
source: '/forgot-password',
destination: 'https://app.supabase.com/forgot-password',
},
{
permanent: true,
source: '/docs/guides/storage-cdn',
destination: '/docs/guides/storage/cdn',
},
{
permanent: true,
source: '/docs/guides/functions/examples',
+110 -3
View File
@@ -1,6 +1,5 @@
import { NextSeo } from 'next-seo'
import _days from '~/components/LaunchWeek/days.json'
import { WeekDayProps } from '~/components/LaunchWeek/types'
import DefaultLayout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
@@ -13,7 +12,20 @@ import classNames from 'classnames'
import styleUtils from '~/components/LaunchWeek/Ticket/utils.module.css'
import { SITE_ORIGIN } from '~/lib/constants'
const days = _days as WeekDayProps[]
import { Badge, IconExternalLink } from '~/../../packages/ui'
const constellation = [
[60, 8],
[13, 20],
[42, 24],
[68, 27],
[23, 42],
[52, 52],
[0, 55],
[33, 65],
[66, 70],
[55, 82],
]
export default function launchweek() {
const { isDarkMode } = useTheme()
@@ -25,6 +37,8 @@ export default function launchweek() {
createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)
)
const [session, setSession] = useState<Session | null>(null)
const [creators, setCreators] = useState<any>([])
const [activeCreator, setActiveCreator] = useState<any>(null)
const { query } = useRouter()
const ticketNumber = query.ticketNumber?.toString()
const defaultUserData = {
@@ -38,12 +52,36 @@ export default function launchweek() {
supabase.auth.onAuthStateChange((event, session) => {
setSession(session)
})
getCreators()
}, [])
useEffect(() => {
document.body.className = isDarkMode ? 'dark bg-[#121212]' : 'light bg-[#fff]'
}, [isDarkMode])
async function getCreators() {
try {
// setLoading(true)
let supa = await supabase.from('lw6_creators').select()
let { data, error, status } = supa
if (error && status !== 406) {
throw error
}
if (data) {
setCreators(data)
}
} catch (error) {
// alert('Error loading user data!')
console.log(error)
} finally {
// setLoading(false)
}
}
return (
<>
<NextSeo
@@ -60,7 +98,7 @@ export default function launchweek() {
}}
/>
<DefaultLayout>
<SectionContainer className="flex flex-col !pb-24 items-center lg:pt-32 gap-32">
<SectionContainer className="flex flex-col !pb-1 items-center lg:pt-32 gap-32">
<div
className={classNames(
styleUtils.appear,
@@ -116,6 +154,75 @@ export default function launchweek() {
)}
></div>
</div>
<SectionContainer
className={classNames(
'flex gap-6 min-h-[350px] !py-3 mb-11 flex-col-reverse md:flex-row',
styleUtils.appear,
styleUtils['appear-third']
)}
>
<div
className={`flex-1 bg-[url('/images/launchweek/orbit.svg')] bg-auto bg-no-repeat bg-bottom relative min-h-[360px]`} //grid grid-cols-5 grid-rows-5
>
{creators.map((creator: any, index: number) => {
return (
<div
className={`justify-self-center absolute overflow-visible`}
onMouseEnter={() => {
setActiveCreator(index)
}}
style={{
top: `${constellation[index][0]}%`,
left: `${constellation[index][1]}%`,
}}
>
<div className="relative group">
<div className="absolute -inset-0.5 bg-brand-1100 rounded-full opacity-75 group-hover:opacity-100 group-hover:blur-sm transition duration-500"></div>
<a href={creator.link} target="_blank" rel="noopener">
<img
className="relative rounded-full w-12 h-12 border border-brand-900 hover:shadow-md"
src={creator.profile_picture}
/>
</a>
</div>
</div>
)
})}
</div>
<div className="flex-1">
<Badge className="mb-6 bg-gradient-to-r from-[#0E3737C2] to-[#67947F] hover:to-[#39617D94] dark:hover:to-[#A6FFD899] text-whiteA-1200 dark:text-black font-normal !py-1 !px-4 dark:from-white dark:via-white dark:to-[#1a7a4c75] bg-slate-1200">
Currently happening
</Badge>
<h2 className="text-4xl dark:text-white mb-2">The Supabase Content Storm</h2>
<p className="text-slate-900 md:max-w-[80%] mb-16">
We worked with +30 content creators from around the world to drop a mountain of
content simultaneously!
<a rel="noopener" target="_blank" href="/blog/the-supabase-content-storm">
<div className="text-brand-900 flex items-center">
See all the content
<IconExternalLink size="small" className="inline-block ml-1" />
</div>
</a>
</p>
{activeCreator !== null && (
<div className="lg:max-w-[50%] min-h-[120px]">
<h3 className="dark:text-white">
{activeCreator !== null
? `${creators[activeCreator].first_name} ${creators[activeCreator].last_name}`
: 'Title'}
</h3>
<p className="text-brand-900">
<a rel="noopener" target="_blank" href={creators[activeCreator].link}>
<span>
{creators[activeCreator].link_title}
<IconExternalLink size="small" className="inline-block ml-2" />
</span>
</a>
</p>
</div>
)}
</div>
</SectionContainer>
</DefaultLayout>
</>
)
@@ -0,0 +1,3 @@
.mask {
mask-image: radial-gradient(black, transparent);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

@@ -0,0 +1,39 @@
<svg width="709" height="355" viewBox="0 0 709 355" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_867_58310)">
<circle cx="355" cy="360" r="101" stroke="url(#paint0_linear_867_58310)" stroke-width="0.685121"/>
<circle cx="355" cy="360" r="157" stroke="url(#paint1_linear_867_58310)" stroke-width="0.685121"/>
<circle cx="355" cy="360" r="225" stroke="url(#paint2_linear_867_58310)" stroke-width="0.685121"/>
<circle cx="355" cy="360" r="285" stroke="url(#paint3_linear_867_58310)" stroke-width="0.685121"/>
<circle cx="355" cy="360" r="360" stroke="url(#paint4_linear_867_58310)" stroke-width="0.685121"/>
</g>
<defs>
<linearGradient id="paint0_linear_867_58310" x1="254" y1="259" x2="456" y2="259" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#121212" stop-opacity="0"/>
<stop offset="0.510996" stop-color="#4F4F4F"/>
<stop offset="0.864583" stop-color="#121212" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_867_58310" x1="198" y1="203" x2="512" y2="203" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#121212" stop-opacity="0"/>
<stop offset="0.510996" stop-color="#4F4F4F"/>
<stop offset="0.864583" stop-color="#121212" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_867_58310" x1="130" y1="135" x2="580" y2="135" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#121212" stop-opacity="0"/>
<stop offset="0.510996" stop-color="#4F4F4F"/>
<stop offset="0.864583" stop-color="#121212" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint3_linear_867_58310" x1="70" y1="75" x2="640" y2="75" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#121212" stop-opacity="0"/>
<stop offset="0.510996" stop-color="#4F4F4F"/>
<stop offset="0.864583" stop-color="#121212" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint4_linear_867_58310" x1="-5" y1="0" x2="715" y2="-2.73533e-06" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#121212" stop-opacity="0"/>
<stop offset="0.510996" stop-color="#4F4F4F"/>
<stop offset="0.864583" stop-color="#121212" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_867_58310">
<rect width="709" height="355" fill="white" transform="matrix(-1 -8.74228e-08 -8.74228e-08 1 709 0)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+141 -134
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -426,7 +426,7 @@ launch week
}
.gradient-container {
min-height: 480px;
min-height: 360px;
position: relative;
max-width: 1600px;
margin: 0 auto;
+169 -8
View File
@@ -120,8 +120,23 @@
"required": false,
"in": "query",
"schema": { "type": "boolean" }
},
{
"name": "import_map",
"required": false,
"in": "query",
"schema": { "type": "boolean" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/CreateFunctionBody" } },
"application/vnd.denoland.eszip": {
"schema": { "$ref": "#/components/schemas/CreateFunctionBody" }
}
}
},
"responses": {
"201": {
"description": "",
@@ -183,12 +198,6 @@
"summary": "Retrieve a function",
"description": "Retrieves a function with the specified slug and project.",
"parameters": [
{
"name": "include_body",
"required": false,
"in": "query",
"schema": { "type": "boolean" }
},
{
"name": "ref",
"required": true,
@@ -250,8 +259,23 @@
"required": false,
"in": "query",
"schema": { "type": "boolean" }
},
{
"name": "import_map",
"required": false,
"in": "query",
"schema": { "type": "boolean" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/UpdateFunctionBody" } },
"application/vnd.denoland.eszip": {
"schema": { "$ref": "#/components/schemas/UpdateFunctionBody" }
}
}
},
"responses": {
"200": {
"description": "",
@@ -294,6 +318,36 @@
"security": [{ "apiKeyHeader": [], "apiKeyParam": [] }, { "bearer": [] }]
}
},
"/v1/projects/{ref}/functions/{function_slug}/body": {
"get": {
"operationId": "getFunctionBody",
"summary": "Retrieve a function body",
"description": "Retrieves a function body for the specified slug and project.",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
},
{
"name": "function_slug",
"required": true,
"in": "path",
"description": "Function slug",
"schema": { "pattern": "/^[A-Za-z0-9_-]+$/", "type": "string" }
}
],
"responses": {
"200": { "description": "" },
"403": { "description": "" },
"500": { "description": "Failed to retrieve function body with given slug" }
},
"tags": ["projects"],
"security": [{ "apiKeyHeader": [], "apiKeyParam": [] }, { "bearer": [] }]
}
},
"/v1/projects/{ref}/custom-hostname": {
"get": {
"operationId": "getCustomHostnameConfig",
@@ -683,6 +737,72 @@
"tags": ["network bans (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/network-restrictions": {
"get": {
"operationId": "getNetworkRestrictions",
"summary": "Gets project's network restrictions",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/NetworkRestrictionsResponse" }
}
}
},
"403": { "description": "" },
"500": { "description": "Failed to retrieve project's network restrictions" }
},
"tags": ["network restrictions (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/network-restrictions/apply": {
"post": {
"operationId": "applyNetworkRestrictions",
"summary": "Updates project's network restrictions",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/NetworkRestrictionsRequest" }
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/NetworkRestrictionsResponse" }
}
}
},
"403": { "description": "" },
"500": { "description": "Failed to update project network restrictions" }
},
"tags": ["network restrictions (beta)"],
"security": [{ "bearer": [] }]
}
}
},
"info": { "title": "Supabase API (v1)", "description": "", "version": "1.0.0", "contact": {} },
@@ -694,6 +814,11 @@
"components": {
"securitySchemes": { "bearer": { "scheme": "bearer", "bearerFormat": "JWT", "type": "http" } },
"schemas": {
"DatabaseResponse": {
"type": "object",
"properties": { "host": { "type": "string" }, "version": { "type": "string" } },
"required": ["host", "version"]
},
"ProjectResponse": {
"type": "object",
"properties": {
@@ -701,7 +826,8 @@
"organization_id": { "type": "string" },
"name": { "type": "string" },
"region": { "type": "string" },
"created_at": { "type": "string" }
"created_at": { "type": "string" },
"database": { "$ref": "#/components/schemas/DatabaseResponse" }
},
"required": ["id", "organization_id", "name", "region", "created_at"]
},
@@ -723,6 +849,7 @@
"ap-southeast-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-central-1",
"ca-central-1",
"ap-south-1",
@@ -743,6 +870,16 @@
"properties": { "name": { "type": "string" } },
"required": ["name"]
},
"CreateFunctionBody": {
"type": "object",
"properties": {
"slug": { "type": "string", "pattern": "/^[A-Za-z0-9_-]+$/" },
"name": { "type": "string" },
"body": { "type": "string" },
"verify_jwt": { "type": "boolean" }
},
"required": ["slug", "name", "body"]
},
"FunctionResponse": {
"type": "object",
"properties": {
@@ -753,7 +890,8 @@
"version": { "type": "number" },
"created_at": { "type": "number" },
"updated_at": { "type": "number" },
"verify_jwt": { "type": "boolean" }
"verify_jwt": { "type": "boolean" },
"import_map": { "type": "boolean" }
},
"required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"]
},
@@ -768,10 +906,19 @@
"created_at": { "type": "number" },
"updated_at": { "type": "number" },
"verify_jwt": { "type": "boolean" },
"import_map": { "type": "boolean" },
"body": { "type": "string" }
},
"required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"]
},
"UpdateFunctionBody": {
"type": "object",
"properties": {
"name": { "type": "string" },
"body": { "type": "string" },
"verify_jwt": { "type": "boolean" }
}
},
"UpdateCustomHostnameResponse": {
"type": "object",
"properties": {
@@ -829,6 +976,20 @@
"type": "object",
"properties": { "ipv4_addresses": { "type": "array", "items": { "type": "string" } } },
"required": ["ipv4_addresses"]
},
"NetworkRestrictionsRequest": {
"type": "object",
"properties": { "dbAllowedCidrs": { "type": "array", "items": { "type": "string" } } },
"required": ["dbAllowedCidrs"]
},
"NetworkRestrictionsResponse": {
"type": "object",
"properties": {
"entitlement": { "enum": ["disallowed", "allowed"], "type": "string" },
"config": { "$ref": "#/components/schemas/NetworkRestrictionsRequest" },
"status": { "enum": ["stored", "applied"], "type": "string" }
},
"required": ["entitlement", "config", "status"]
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+86 -65
View File
@@ -718,7 +718,15 @@
"schema": {
"type": "object",
"properties": {
"expiresIn": { "type": "integer", "minimum": 1, "example": 60000 }
"expiresIn": { "type": "integer", "minimum": 1, "example": 60000 },
"transform": {
"type": "object",
"properties": {
"height": { "type": "integer", "minimum": 0, "example": 100 },
"width": { "type": "integer", "minimum": 0, "example": 100 },
"resize": { "type": "string", "enum": ["cover", "contain", "fill"] }
}
}
},
"required": ["expiresIn"]
}
@@ -1078,6 +1086,83 @@
}
}
},
"/object/info/authenticated/{bucketName}/{wildcard}": {
"get": {
"summary": "Retrieve object info",
"tags": ["object"],
"parameters": [
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": { "type": "string" },
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/def-1", "description": "Error response" }
}
}
}
}
}
},
"/object/info/{bucketName}/{wildcard}": {
"get": {
"summary": "Retrieve object info",
"tags": ["deprecated"],
"description": "use HEAD /object/authenticated/{bucketName} instead",
"parameters": [
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": { "type": "string" },
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"4XX": {
"description": "Default Response",
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/def-1" } }
}
}
}
}
},
"/object/copy": {
"post": {
"summary": "Copies an object",
@@ -1195,70 +1280,6 @@
}
}
}
},
"/render/authenticated/{bucketName}/{wildcard}": {
"get": {
"summary": "Render an authenticated image with the given transformations",
"tags": ["object"],
"parameters": [
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/def-1", "description": "Error response" }
}
}
}
}
}
},
"/render/public/{bucketName}/{wildcard}": {
"get": {
"summary": "Render a public image with the given transformations",
"tags": ["object"],
"parameters": [
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/def-1", "description": "Error response" }
}
}
}
}
}
}
},
"tags": [
+441 -8
View File
@@ -31,6 +31,18 @@
},
"created_at": {
"type": "string"
},
"database": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": ["host", "version"]
}
},
"required": ["id", "organization_id", "name", "region", "created_at"]
@@ -82,6 +94,7 @@
"ap-southeast-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-central-1",
"ca-central-1",
"ap-south-1",
@@ -119,6 +132,18 @@
},
"created_at": {
"type": "string"
},
"database": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": ["host", "version"]
}
},
"required": ["id", "organization_id", "name", "region", "created_at"]
@@ -268,8 +293,63 @@
"schema": {
"type": "boolean"
}
},
{
"name": "import_map",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"slug": {
"type": "string",
"pattern": "/^[A-Za-z0-9_-]+$/"
},
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
},
"required": ["slug", "name", "body"]
}
},
"application/vnd.denoland.eszip": {
"schema": {
"type": "object",
"properties": {
"slug": {
"type": "string",
"pattern": "/^[A-Za-z0-9_-]+$/"
},
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
},
"required": ["slug", "name", "body"]
}
}
}
},
"responses": {
"201": {
"description": "",
@@ -302,6 +382,9 @@
},
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
}
},
"required": [
@@ -393,6 +476,9 @@
},
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
}
},
"required": [
@@ -441,14 +527,6 @@
"summary": "Retrieve a function",
"description": "Retrieves a function with the specified slug and project.",
"parameters": [
{
"name": "include_body",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "ref",
"required": true,
@@ -504,6 +582,9 @@
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
},
"body": {
"type": "string"
}
@@ -589,8 +670,53 @@
"schema": {
"type": "boolean"
}
},
{
"name": "import_map",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
}
}
},
"application/vnd.denoland.eszip": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
}
}
}
}
},
"responses": {
"200": {
"description": "",
@@ -623,6 +749,9 @@
},
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
}
},
"required": [
@@ -706,6 +835,57 @@
]
}
},
"/v1/projects/{ref}/functions/{function_slug}/body": {
"get": {
"operationId": "getFunctionBody",
"summary": "Retrieve a function body",
"description": "Retrieves a function body for the specified slug and project.",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": {
"minLength": 20,
"maxLength": 20,
"type": "string"
}
},
{
"name": "function_slug",
"required": true,
"in": "path",
"description": "Function slug",
"schema": {
"pattern": "/^[A-Za-z0-9_-]+$/",
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
},
"403": {
"description": ""
},
"500": {
"description": "Failed to retrieve function body with given slug"
}
},
"tags": ["projects"],
"security": [
{
"apiKeyHeader": [],
"apiKeyParam": []
},
{
"bearer": []
}
]
}
},
"/v1/projects/{ref}/custom-hostname": {
"get": {
"operationId": "getCustomHostnameConfig",
@@ -1454,6 +1634,157 @@
}
]
}
},
"/v1/projects/{ref}/network-restrictions": {
"get": {
"operationId": "getNetworkRestrictions",
"summary": "Gets project's network restrictions",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": {
"minLength": 20,
"maxLength": 20,
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"entitlement": {
"enum": ["disallowed", "allowed"],
"type": "string"
},
"config": {
"type": "object",
"properties": {
"dbAllowedCidrs": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["dbAllowedCidrs"]
},
"status": {
"enum": ["stored", "applied"],
"type": "string"
}
},
"required": ["entitlement", "config", "status"]
}
}
}
},
"403": {
"description": ""
},
"500": {
"description": "Failed to retrieve project's network restrictions"
}
},
"tags": ["network restrictions (beta)"],
"security": [
{
"bearer": []
}
]
}
},
"/v1/projects/{ref}/network-restrictions/apply": {
"post": {
"operationId": "applyNetworkRestrictions",
"summary": "Updates project's network restrictions",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": {
"minLength": 20,
"maxLength": 20,
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"dbAllowedCidrs": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["dbAllowedCidrs"]
}
}
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"entitlement": {
"enum": ["disallowed", "allowed"],
"type": "string"
},
"config": {
"type": "object",
"properties": {
"dbAllowedCidrs": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["dbAllowedCidrs"]
},
"status": {
"enum": ["stored", "applied"],
"type": "string"
}
},
"required": ["entitlement", "config", "status"]
}
}
}
},
"403": {
"description": ""
},
"500": {
"description": "Failed to update project network restrictions"
}
},
"tags": ["network restrictions (beta)"],
"security": [
{
"bearer": []
}
]
}
}
},
"info": {
@@ -1482,6 +1813,18 @@
}
},
"schemas": {
"DatabaseResponse": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": ["host", "version"]
},
"ProjectResponse": {
"type": "object",
"properties": {
@@ -1499,6 +1842,18 @@
},
"created_at": {
"type": "string"
},
"database": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": ["host", "version"]
}
},
"required": ["id", "organization_id", "name", "region", "created_at"]
@@ -1530,6 +1885,7 @@
"ap-southeast-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-central-1",
"ca-central-1",
"ap-south-1",
@@ -1563,6 +1919,25 @@
},
"required": ["name"]
},
"CreateFunctionBody": {
"type": "object",
"properties": {
"slug": {
"type": "string",
"pattern": "/^[A-Za-z0-9_-]+$/"
},
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
},
"required": ["slug", "name", "body"]
},
"FunctionResponse": {
"type": "object",
"properties": {
@@ -1590,6 +1965,9 @@
},
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
}
},
"required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"]
@@ -1622,12 +2000,29 @@
"verify_jwt": {
"type": "boolean"
},
"import_map": {
"type": "boolean"
},
"body": {
"type": "string"
}
},
"required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"]
},
"UpdateFunctionBody": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"body": {
"type": "string"
},
"verify_jwt": {
"type": "boolean"
}
}
},
"UpdateCustomHostnameResponse": {
"type": "object",
"properties": {
@@ -1725,6 +2120,44 @@
}
},
"required": ["ipv4_addresses"]
},
"NetworkRestrictionsRequest": {
"type": "object",
"properties": {
"dbAllowedCidrs": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["dbAllowedCidrs"]
},
"NetworkRestrictionsResponse": {
"type": "object",
"properties": {
"entitlement": {
"enum": ["disallowed", "allowed"],
"type": "string"
},
"config": {
"type": "object",
"properties": {
"dbAllowedCidrs": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["dbAllowedCidrs"]
},
"status": {
"enum": ["stored", "applied"],
"type": "string"
}
},
"required": ["entitlement", "config", "status"]
}
}
}
+145 -108
View File
@@ -1111,6 +1111,25 @@
"type": "integer",
"minimum": 1,
"example": 60000
},
"transform": {
"type": "object",
"properties": {
"height": {
"type": "integer",
"minimum": 0,
"example": 100
},
"width": {
"type": "integer",
"minimum": 0,
"example": 100
},
"resize": {
"type": "string",
"enum": ["cover", "contain", "fill"]
}
}
}
},
"required": ["expiresIn"]
@@ -1685,6 +1704,132 @@
}
}
},
"/object/info/authenticated/{bucketName}/{wildcard}": {
"get": {
"summary": "Retrieve object info",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": {
"type": "string"
},
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"description": "Error response",
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
}
},
"/object/info/{bucketName}/{wildcard}": {
"get": {
"summary": "Retrieve object info",
"tags": ["deprecated"],
"description": "use HEAD /object/authenticated/{bucketName} instead",
"parameters": [
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": {
"type": "string"
},
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"4XX": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
}
},
"/object/copy": {
"post": {
"summary": "Copies an object",
@@ -1877,114 +2022,6 @@
}
}
}
},
"/render/authenticated/{bucketName}/{wildcard}": {
"get": {
"summary": "Render an authenticated image with the given transformations",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"description": "Error response",
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
}
},
"/render/public/{bucketName}/{wildcard}": {
"get": {
"summary": "Render a public image with the given transformations",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"description": "Error response",
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
}
}
},
"tags": [
@@ -86,8 +86,8 @@ const PITRSelection = ({}) => {
// Start: Variables specifically for date picker component
// Required as it only works with vanilla Date object which is not timezone localized
const earliestAvailableBackupFormatted = new Date(earliestAvailableBackup.format('DD-MMM-YYYY'))
const latestAvailableBackupFormatted = new Date(latestAvailableBackup.format('DD-MMM-YYYY'))
const earliestAvailableBackupFormatted = new Date(earliestAvailableBackup.format('YYYY-MM-DD'))
const latestAvailableBackupFormatted = new Date(latestAvailableBackup.format('YYYY-MM-DD'))
const isSelectedOnEarliest = checkMatchingDates(selectedDate, earliestAvailableBackupFormatted)
const isSelectedOnLatest = checkMatchingDates(selectedDate, latestAvailableBackupFormatted)
const availableDates = getDatesBetweenRange(
@@ -23,7 +23,7 @@ interface Props {
sidePanelKey?: 'row' | 'column' | 'table'
/** Toggles if we're duplicating a table */
isDuplicating: boolean
/** Selected entities if we're editting a row, column or table */
/** Selected entities if we're editing a row, column or table */
selectedRowToEdit?: Dictionary<any>
selectedColumnToEdit?: PostgresColumn
selectedTableToEdit?: PostgresTable