Merge branch 'master' of github.com:supabase/supabase

This commit is contained in:
Paul Copplestone committed 2021-07-28 12:09:00 +08:00
commit da35f0f14f
22 files changed
+224 -22

No files matched your search

+1 -1
View File
@@ -138,7 +138,7 @@ values={[
```sh
1. Go to the "API" section.
2. Find "todos" in the "Tables an Views" section.
2. Find "todos" in the "Tables and Views" section.
3. Switch between the Javascript and the cURL docs using the tabs.
```
+2 -2
View File
@@ -128,7 +128,7 @@ returns smallint as $$
var num_affected = plv8.execute(
'udpate profiles set first_name = $1 where id = $2',
[id, first_name]
[first_name, id]
);
return num_affected;
@@ -155,4 +155,4 @@ $$ language plv8;
## Resources
- Official [`plv8` documentation](https://plv8.github.io/).
- [plv8 Github Repository](https://github.com/plv8/plv8).
- [plv8 Github Repository](https://github.com/plv8/plv8).
+1 -2
View File
@@ -17,7 +17,6 @@ Our CLI is still under heavy development, and is missing some features:
- You cannot yet deploy your local changes to your live project using the CLI. You will need to take a "dump" of your database schema
and run it on your live database.
- We have not yet added Storage to the local development suite.
- The self-hosted version of Supabase does not include a UI yet.
We are working on this in stages, starting with our [UI library](https://github.com/supabase/ui)
([more context](https://github.com/supabase/supabase/discussions/1001#discussioncomment-558696)).
@@ -33,7 +32,7 @@ In the meantime, here are some suggested tools for interacting with your Postgre
## Prerequisites
Our CLI makes heavy use of [Docker Compose](https://docs.docker.com/compose/install), so make sure it is installed and configured to
[run with elevated priveleges][https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user].
[run with elevated priveleges](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
You will also need to install [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).
+39 -13
View File
@@ -22,7 +22,7 @@ By the end of this guide you'll have an app which allows users to login and upda
<img height="500px" src="/img/supabase-flutter-demo.png" alt="Supabase User Management example" />
### Github
Whenever you get stuck at any point, take a look at [this repo](https://github.com/dshukertjr/flutter_supabase_quickstart).
Whenever you get stuck at any point, take a look at [this repo](https://github.com/supasquad/supabase-flutter-quickstart).
## Project set up
@@ -161,7 +161,7 @@ Then let's install the only additional dependency: [supabase-flutter](https://gi
Open the app and copy and paste the following inside `pubspec.yaml` under `dependencies`.
```yaml
supabase_flutter: ^0.0.4
supabase_flutter: ^0.0.6
```
Run `flutter pub get` to install the dependencies.
@@ -283,6 +283,26 @@ class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
}
```
### Set up AuthRequiredState
We might want to show certain pages to the users only if they are signed in.
For that we can create a handy `AuthRequiredState` class that we can inherit from for pages where the users need to be authenticated.
`AuthRequiredState` will inherit `SupabaseAuthRequiredState` which is provided by `supabase_flutter` package.
```dart title="lib/components/auth_required_state.dart"
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class AuthRequiredState<T extends StatefulWidget>
extends SupabaseAuthRequiredState<T> {
@override
void onUnauthenticated() {
/// Users will be sent back to the LoginPage if they sign out.
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
}
}
```
Let's also create a constant file to make it easier to use Supabase client.
```dart title="lib/utils/constants.dart"
@@ -412,13 +432,14 @@ class _LoginPageState extends AuthState<LoginPage> {
### Set up Account page
After a user is signed in we can allow them to edit their profile details and manage their account.
Let's create a new component for that called `account_page.dart`.
Note that this page will also inherit `AuthState` as it will handle user sign out.
Let's create a new widget called `account_page.dart` for that.
Note that this page will inherit `AuthRequiredState` as user needs to be authenticated to view this page.
```dart title="lib/pages/account_page.dart"
import 'package:flutter/material.dart';
import 'package:supabase_flutter_guide/components/auth_state.dart';
import 'package:supabase_flutter_guide/components/auth_required_state.dart';
import 'package:supabase_flutter_guide/utils/constants.dart';
import 'package:supabase/supabase.dart';
class AccountPage extends StatefulWidget {
const AccountPage({Key? key}) : super(key: key);
@@ -427,20 +448,19 @@ class AccountPage extends StatefulWidget {
_AccountPageState createState() => _AccountPageState();
}
class _AccountPageState extends AuthState<AccountPage> {
class _AccountPageState extends AuthRequiredState<AccountPage> {
late final _usernameController = TextEditingController();
late final _websiteController = TextEditingController();
var _loading = false;
Future<void> _getProfile() async {
Future<void> _getProfile(String userId) async {
setState(() {
_loading = true;
});
final user = supabase.auth.user()!;
final response = await supabase
.from('profiles')
.select()
.eq('id', user.id)
.eq('id', userId)
.single()
.execute();
if (response.error != null && response.status != 406) {
@@ -496,9 +516,16 @@ class _AccountPageState extends AuthState<AccountPage> {
}
@override
void initState() {
_getProfile();
super.initState();
void onAuthenticated(Session session) {
final user = session.user;
if (user != null) {
_getProfile(user.id);
}
}
@override
void onUnauthenticated() {
Navigator.of(context).pushReplacementNamed('/login');
}
@override
@@ -538,7 +565,6 @@ class _AccountPageState extends AuthState<AccountPage> {
```
### Launch!
Now that we have all the components in place, let's update `lib/main.dart`:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 79 KiB

@@ -87,8 +87,8 @@ Postgres, and his data structure will enable future development.
With Supabase, Tyler can use Flutter to build a performant app quickly at a low cost. Tyler is now a massive fan of the Supabase
experience and has even joined the SupaSquad.
You can download and install spot for [Android](https://apps.apple.com/us/app/spot-videos/id1564675926?utm_source=supabase&utm_campaign=static)
and [iOS](https://play.google.com/store/apps/details?id=app.spotvideo&utm_source=supabase&utm_campaign=static)
You can download and install spot for [iOS](https://apps.apple.com/us/app/spot-videos/id1564675926?utm_source=supabase&utm_campaign=static)
and [Android](https://play.google.com/store/apps/details?id=app.spotvideo&utm_source=supabase&utm_campaign=static)
to see just how snappy his setup is.
Tyler has fully open-sourced his example - you can [clone the repo](https://github.com/dshukertjr/spot)
and use it as the basis of your next big idea.
and use it as the basis of your next big idea.
+169
View File
@@ -0,0 +1,169 @@
---
title: 'Supabase Storage now in Beta'
description: Supabase Storage moves into Beta.
author: inian
image: launch-week-sql-day-2/supabase-storage-beta-og.jpg
thumb: launch-week-sql-day-2/supabase-storage-beta.jpg
tags:
- storage
- launch-week
date: '2021-07-27'
toc_depth: 2
---
At Supabase, one of our core values is [Kaizen](https://en.wikipedia.org/wiki/Kaizen) - continuous improvement. And that's exactly what we've been doing with Storage since it [launched](https://supabase.io/blog/2021/03/30/supabase-storage) three months ago. Today, we are launching the Sequel to Storage Alpha (I bet you didn't see that coming): Storage Beta!
## Streaming Media
We've added support for streaming audio and video files.
Clients can use the `Content-Range` HTTP header to request specific parts of a file from a server. This allows them to intelligently download the parts of the video that a user is viewing, without buffering irrelevant sections of the media file. Supabase Storage now supports this header, making it easier to host and watch [nyan cat videos](https://www.youtube.com/watch?v=SkgTxQm9DWM) all day long.
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
<source
src="/new/videos/blog/launch-week-storage-2/nyan-cat.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Public Buckets
Public Buckets have been one of our most requested features. We launched without them because there are too [many horror stories](https://www.google.com/search?q=s3+bucket+negligence+award&oq=s3+bucket+negligence+award) of S3 buckets unintentionally exposing objects. We wanted to take the time to implement safeguards against this.
To enable this feature safely, buckets are made private by default, with an extremely prominent warning in the dashboard when you choose to make them public.
You can make objects public in S3 via multiple mechanisms (e.g. tags, or prefixes). While this allows for flexibility, it makes it hard to discover publicly exposed objects. To prevent any confusion, we decided that buckets must be public in their entirety. This public visibility straightforward - if it's in a public bucket, it's public!
Objects in public buckets can be accessed via a URL without any Authorization tokens or headers. This makes them perfect for hosting assets for your web or mobile application.
Public buckets still require [Auth Policies](https://supabase.io/docs/guides/storage#policy-examples) to upload and delete objects, allowing you to securely manage their contents.
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
<source src="/new/images/blog/2021-june/public-buckets.mp4" type="video/mp4" muted playsInline />
</video>
## Directory uploads
You can now upload an entire directory to Supabase Storage and the directory structure is fully preserved after the upload. We used the [File and Directory entries API](https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API) for implementing this. This is a non-standard API, but we didn't find any compatibility issues in the browsers we support. So, now you can upload the [Storage Github repo](https://github.com/supabase/storage-api/) to storage 🤓
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
<source
src="/new/videos/blog/launch-week-storage-2/directory-uploads.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## A New Policy Editor
Postgres [Row Level Security](https://www.postgresql.org/docs/13/ddl-rowsecurity.html) (RLS) is at the core of Supabase Storage and Auth. RLS lets you define complex policies, tightly integrated with Supabase Auth users, using the language you're already comfortable with - SQL.
However, getting started with RLS can be daunting. To make it more approachable for beginners, we've included a set of pre-defined templates on our Dashboard, covering common use-cases.
![Policy editor templates](/new/images/blog/launch-week-sql-day-2/policy-editor-1.png)
Once you've selected a template, you choose which operations to allow and the Dashboard determines which API functions can access the bucket. For example, a user with INSERT permissions will be able to call the `createObject`, `copyObject` and `getSignedObject` functions in the `supabase-js` library.
![Policy editor permissions](/new/images/blog/launch-week-sql-day-2/policy-editor-2.png)
After writing the policy definition (which can be any valid SQL expression), you get an opportunity to review the final policy before saving. We made sure that there is no magic going on behind the scenes: you can always see the underlying SQL definition of the policies. As you become more comfortable with Row Level Security, you can define these policies directly using our SQL editor.
## Using Storage in Local development
It took some time to enable Storage on self-hosted Supabase. We wanted to provide a completely local experience during development, but storage had a hard dependency on an object storage service like S3. This required developers to create an S3 bucket, an IAM user in AWS, and add the credentials of the IAM user to the local setup, which was far from an ideal experience.
From day 1, Supabase Storage was designed so that it would be easy to add new Storage backends. We knew we'd add more storage options like Google Cloud Storage or Backblaze, but little did we expect that this would be useful for our self-hosting setup! We implemented a new Storage Backend which [use a local filesystem](https://github.com/supabase/storage-api/blob/master/src/backend/file.ts) for storing objects. You can now get started with Storage without any additional setup, giving you a completely self-contained instance of Supabase.
Check out our updated [self hosting guide](https://supabase.io/docs/guides/self-hosting) and our [CLI](https://github.com/supabase/cli) to get started.
## Upload anything
At launch, you could pass in a `File` object and `supabase-js` used `FormData` to send a request to the storage server to upload the file. This made it easy to send the cache control information and other options directly to the server as a multipart request.
However, `FormData` is only supported in the browser, making `supabase-js` incompatible with Node.js. The simplest way to solve this would have been to include the [FormData polyfill](https://www.npmjs.com/package/form-data) along with the library.
At Supabase, we are [maniacal about performance](https://supabase.io/blog/2020/12/13/supabase-dashboard-performance). Keeping our client libraries lean is a key differentiator. Our entire client library (including the clients for postgrest, storage, realtime and auth) is just 15.8 kb. If you are just interested in using a single service like storage, you can use the `storage-js` library directly which is [even smaller](https://bundlephobia.com/package/@supabase/storage-js@1.4.0). This made including polyfills like Formdata a no-go.
![Supabase JS bundle size](/new/images/blog/launch-week-sql-day-2/supabase-js-size.png)
We also considered shipping separate bundles for Node.js and the browser. This would have avoided polyfills for APIs which are already supported in each browser. However, this comes with an increase in complexity to our build process, and users would need to choose which flavor of the library to use in different environments like React Native, Deno, etc. We want to make our libraries universal.
Instead, we modified the storage server to accept Binary data directly. With this change, you can directly upload binary Data and even NodeJS streams to the storage API.
![NodeJS Stream upload](/new/images/blog/launch-week-sql-day-2/stream-upload.png)
With this change in place, the client library supports uploading `ArrayBuffer`, `ArrayBufferView`, `Blob`, `Buffer`, `File`, `FormData`, `NodeJS.ReadableStream`, `ReadableStream<Uint8Array>` - without any change to the bundle size! This should enable you to use storage from an even wider range of environments.
## Context menus
The storage explorer in our Dashboard feels like using a file explorer in your operating system. There were a lot of challenges to make it feel intuitive and robust, since S3 is a not a traditional filesystem. For example, S3 doesn't support a move operation natively - you need to copy the object to the new location and delete the original object. S3 also doesn't have a concept of directory, which means there is no API call to rename a directory. But to make the storage explorer feel like a native file explorer, we implemented these features.
Context menus on folders
![Context menu 1](/new/images/blog/launch-week-sql-day-2/context-menu-1.png)
Context menus on files
![Context menu 2](/new/images/blog/launch-week-sql-day-2/context-menu-2.png)
### The case of the disappearing folders
As we already mentioned, S3 doesn't really have a concept of directories. So if a user uploads an object with path `dir/subdir/avatar.png`, the dir and subdir are automatically "created" and there is no explicit API call to create them.
This leads to an issue where if a user creates an empty directory and refreshes the page, the directory disappears since it is not persisted to S3. To simulate a normal filesystem (where empty directories are not garbage collected), we upload an empty file when the user creates a directory on the dashboard. The dashboard hides this placeholder file and the placeholder is deleted when the user uploads an object in the directory - voila, no more disappearing directores!
## Performance improvements for large buckets
We significantly improved rendering for a large number of items in the Dashboard. We use a virtualization library to render the objects in view and actively discard DOM elements which are not currently rendered from memory. This makes scrolling through thousands of items buttery smooth.
Here is a demo testing rendering the heaviest object known to mankind - the `node_modules` folder!
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
<source
src="/new/videos/blog/launch-week-storage-2/large-buckets.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## API changes
Supabase Storage now supports `upsert`. Shoutout to [@ankitjena](https://github.com/ankitjena) for
[this Pull Request](https://github.com/supabase/storage-api/pull/32).
![Storage now supports upserts](/new/images/blog/2021-june/supabase-storage-upsert.png)
We also have automated API docs generated [here](https://supabase.github.io/storage-api/#/) if you want to use the Storage API directly.
### Storage in the wild
We have a few production applications using Supabase Storage. Wataru is using Storage to power his community site [Shikutoku](https://shikutoku.me/) and Tyler is using Supabase Storage to store short video clips uploaded to his [Spot app](https://supabase.io/blog/2021/07/27/spot-flutter-with-postgres) built with Flutter
<Quote img="tyler-spot.jpg" caption="Tyler Shukert, creator of Spot">
<p>
As soon as I saw Supabase I knew it was the perfect technology to use alongside Flutter to build
apps faster than ever. For apps like Spot where we handle user submitted files, it is very easy
to manage them securely.
</p>
<p>
Supabaseを最初発見した時にこれとFlutterを組み合わせれば今まで以上に爆速でアプリ開発ができるだろうと思いました。Spotのようにユーザーがファイルを投稿するアプリの場合でもセキュアに取り扱うのが簡単で本当に助かります。
</p>
</Quote>
<Quote img="wataru.jpeg" caption="Wataru Yonamine, creator of Shikutoku">
<p>
I think it’s a great service, simple and scalable. I like that the dashboard makes it easy to
check and search for images.
</p>
<p>
シンプルで拡張性のある素晴らしいサービスだと思います。ダッシュボードで画像が確認しやすく、検索できるのもいいですね。
</p>
</Quote>
## What's next
We're planning a Content Delivery Network for faster downloads, as well as basic transformation and optimization support for media files (like resizing, etc). We will continue our Kaizen on smaller improvements like allowing configurable upload limits and improving service stability and scalability.
Anything else you want to see or can help implement in Storage? Reach out on our [Discord channel](https://discord.supabase.com/) and give Storage a try by [creating a project](https://app.supabase.io/) on Supabase!
+1 -1
View File
@@ -58,7 +58,7 @@ const { data, error } = await supabase
const { data, error } = await supabase
.storage
.from('avatars')
.move('pubic/space-cat.png', 'private/space-cat.png')
.move('public/space-cat.png', 'private/space-cat.png')
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

+8
View File
@@ -8,6 +8,14 @@
<lastBuildDate>Mon, 26 Jul 2021 16:00:00 GMT</lastBuildDate>
<atom:link href="https://supabase.io/blog/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.io/blog/2021/07/27/storage-beta</guid>
<title>Supabase Storage now in Beta</title>
<link>https://supabase.io/blog/2021/07/27/storage-beta</link>
<description>Supabase Storage moves into Beta.</description>
<pubDate>Mon, 26 Jul 2021 16:00:00 GMT</pubDate>
</item>
<item>
<guid>https://supabase.io/blog/2021/07/27/spot-flutter-with-postgres</guid>
<title>Spot: a video sharing app built with Flutter</title>