diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b93f36c2483..5d9f46f73b2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,4 @@ /studio/ @supabase/frontend /apps/www/ @supabase/frontend +/apps/reference/ @supabase/docs +/spec/ @supabase/docs diff --git a/.github/workflows/docs-compilation-check.yml b/.github/workflows/docs-compilation-check.yml index ce774357678..0c41676a3a6 100644 --- a/.github/workflows/docs-compilation-check.yml +++ b/.github/workflows/docs-compilation-check.yml @@ -4,12 +4,10 @@ name: Docs Compilation Check on: - push: - branches: [master] pull_request: branches: [master] paths: - - 'web/**' + - 'apps/reference/**' jobs: build: @@ -37,12 +35,8 @@ jobs: - name: Install Deps run: npm ci - working-directory: ./web - - - name: Pull Specs - run: make - working-directory: ./web/spec + working-directory: ./apps/reference - name: Build run: npm run build - working-directory: ./web + working-directory: ./apps/reference diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 34150c7c715..7d798d837a8 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -48,9 +48,9 @@ jobs: - name: Run Test run: npm run test - continue-on-error: true - name: Stop infrastructure + if: always() run: npm run docker:down - name: Get Allure history diff --git a/.github/workflows/publish_docker_hub.yml b/.github/workflows/publish_docker_hub.yml deleted file mode 100644 index a3aecce6d10..00000000000 --- a/.github/workflows/publish_docker_hub.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Publish to Docker Hub - -on: - push: - branches: - - studio - paths: - - 'studio/**' - workflow_dispatch: - -jobs: - publish: - name: Publish to Docker Hub - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - - uses: docker/setup-qemu-action@v1 - with: - platforms: amd64,arm64 - - - uses: docker/setup-buildx-action@v1 - - - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - uses: docker/build-push-action@v2 - with: - context: studio - platforms: linux/amd64,linux/arm64 - push: true - tags: supabase/studio:latest - target: production diff --git a/.github/workflows/publish_image.yml b/.github/workflows/publish_image.yml new file mode 100644 index 00000000000..8ed1db87295 --- /dev/null +++ b/.github/workflows/publish_image.yml @@ -0,0 +1,57 @@ +name: Publish to Image Registry + +on: + push: + tags: + - '*' + workflow_dispatch: + inputs: + version: + description: 'Image tag' + required: true + type: string + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - id: meta + uses: docker/metadata-action@v4 + with: + images: | + supabase/studio + public.ecr.aws/t3w2s2c9/studio + flavor: | + latest=false + tags: | + type=ref,event=tag + type=raw,value=${{ inputs.version }},enable=${{ github.event_name != 'push' }} + + - uses: docker/setup-qemu-action@v2 + with: + platforms: amd64,arm64 + + - uses: docker/setup-buildx-action@v2 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to ECR + uses: docker/login-action@v2 + with: + registry: public.ecr.aws + username: ${{ secrets.PROD_ACCESS_KEY_ID }} + password: ${{ secrets.PROD_SECRET_ACCESS_KEY }} + + - uses: docker/build-push-action@v3 + with: + push: true + context: '{{defaultContext}}:studio' + target: production + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/studio-build.yml b/.github/workflows/studio-build.yml index bb90e12f18c..b51253bbf04 100644 --- a/.github/workflows/studio-build.yml +++ b/.github/workflows/studio-build.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/.github/workflows/studio-tests.yml b/.github/workflows/studio-tests.yml index fa0dc31697b..f9d28288a50 100644 --- a/.github/workflows/studio-tests.yml +++ b/.github/workflows/studio-tests.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: @@ -28,8 +28,8 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Install deps - run: npm i - working-directory: ./studio + run: npm install + working-directory: ./ - name: Run tests run: npm test working-directory: ./studio diff --git a/.turbo-cookie b/.turbo-cookie new file mode 100755 index 00000000000..9e5d1817106 --- /dev/null +++ b/.turbo-cookie @@ -0,0 +1 @@ +cookie \ No newline at end of file diff --git a/DEVELOPERS.md b/DEVELOPERS.md index e92a19bdc45..a0dd47cb371 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -1,64 +1,60 @@ # Developing Supabase -- [Development Setup](#development-setup) - - [Installing Dependencies](#installing-dependencies) - - [Forking Supabase on GitHub](#forking-supabase-on-github) -- [Building Supabase](#building-supabase) - - [Choosing Directory](#choosing-directory) -- [Start a Development Server](#start-a-development-server) - - [Supabase Website Development Server](#supabase-website-development-server) - - [Supabase Docs Development Server](#supabase-docs-development-server) - - [Supabase Studio Development Server](#supabase-studio-development-server) +1. [Development setup](#development-setup) + - [Install dependencies](#install-dependencies) + - [Fork the repository](#fork-the-repository) +1. [Build Supabase](#build-supabase) + - [Choose a directory](#choose-a-directory) +1. [Start a development server](#start-a-development-server) + - [Supabase Website](#supabase-website) + - [Supabase Docs](#supabase-docs) + - [Supabase Studio](#supabase-studio) +1. [Create a pull request](#create-a-pull-request) + +- [Common tasks](#common-tasks) + - [Add a redirect](#add-a-redirect) - [Monorepo](#monorepo) - [Getting started](#getting-started) - [Shared components](#shared-components) - [Installing packages](#installing-packages) - [Development](#development) -- [Common Tasks](#common-tasks) - - [Adding redirects](#adding-redirects) -- [Finally](#finally) -- [Community Channels](#community-channels) +- [Community channels](#community-channels) -## Development Setup +## Development setup -First off, thanks for your interest in Supabase and for wanting to contribute! before you begin, read the +Thanks for your interest in Supabase and for wanting to contribute! Before you begin, read the [code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) and check out the [existing issues](https://github.com/supabase/supabase/issues). This document describes how to set up your development environment to build and test Supabase. -### Installing Dependencies +### Install dependencies -Before you can build Supabase, you must install and configure the following dependencies on your -machine: +You need to install and configure the following dependencies on your machine to build Supabase: - [Git](http://git-scm.com/) - - [Node.js v16.x (LTS)](http://nodejs.org) +- [npm](https://www.npmjs.com/) version 7+ or [Yarn](https://yarnpkg.com/) -- [npm](https://www.npmjs.com/) version 7+. +### Fork the repository -### Forking Supabase on GitHub +To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase). -To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase). After you fork the repository, you may now begin editing the source code. +## Build Supabase -## Building Supabase - -To build Supabase, you clone the source code repository: - -2. Clone your GitHub forked repository: +1. Clone your GitHub forked repository: ```sh git clone https://github.com//supabase.git ``` -3. Go to the Supabase directory: +1. Go to the Supabase directory: ```sh cd supabase ``` -### Choosing Directory +### Choose a directory -Before you start a development server, you must choose if you want to work on the [Supabase Website](https://supabase.com), [Supabase Docs](https://supabase.com/docs), or [Supabase Studio](https://app.supabase.com). +Choose if you want to work on the [Supabase Website](https://supabase.com), [Supabase Docs](https://supabase.com/docs), or [Supabase Studio](https://app.supabase.com). 1. Go to the [Supabase Website](https://supabase.com) directory @@ -69,7 +65,7 @@ Before you start a development server, you must choose if you want to work on th Go to the [Supabase Docs](https://supabase.com/docs) directory ```sh - cd web + cd apps/reference ``` Go to the [Supabase Studio](https://app.supabase.com) directory @@ -78,7 +74,7 @@ Before you start a development server, you must choose if you want to work on th cd studio ``` -2. Install npm dependencies: +1. Install npm/yarn dependencies: npm @@ -92,19 +88,19 @@ Before you start a development server, you must choose if you want to work on th yarn install ``` -## Start a Development Server +## Start a development server -To debug code, and to see changes in real time, it is often useful to have a local HTTP server. Click one of the three links below to choose which development server you want to start. +To debug code and to see your changes in real time, it is often useful to have a local HTTP server. Click one of the three links below to choose which development server you want to start. -- [Supabase Website](#Supabase-Website-Development-Server) -- [Supabase Docs](#Supabase-Docs-Development-Server) -- [Supabase Studio](#Supabase-Studio-Development-Server) +- [Supabase Website](#supabase-website) +- [Supabase Docs](#supabase-docs) +- [Supabase Studio](#supabase-studio) -### Supabase Website Development Server +### Supabase Website The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) section below. -### Supabase Docs Development Server +### Supabase Docs 1. Build development server @@ -120,7 +116,7 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec yarn build ``` -2. Start development server +1. Start development server npm @@ -134,13 +130,9 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec yarn start ``` -3. To access the local server, enter the following URL into your web browser: +1. Access the local server in your web browser at http://localhost:3010/docs. - ```sh - http://localhost:3005/docs - ``` - -### Supabase Studio Development Server +### Supabase Studio 1. Start development server @@ -156,13 +148,22 @@ The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) sec yarn dev ``` -2. To access the local server, enter the following URL into your web browser: +1. Access the local server in your web browser at http://localhost:8082/. +See the [Supabase Studio readme](./studio/README.md) for more information. - ```sh - http://localhost:8082/ - ``` +## Create a pull request -For more information on Supabase Studio, see the [Supabase Studio readme](./studio/README.md). +After making your changes, open a pull request (PR). Once you submit your pull request, others from the Supabase team/community will review it with you. + +Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors). + +--- + +## Common tasks + +### Add a redirect + +Create a new entry in the [`next.config.js`](https://github.com/supabase/supabase/blob/master/apps/www/next.config.js) file in our main site. ## Monorepo @@ -179,14 +180,12 @@ npm run dev # start all the applications Then edit and visit any of the following sites: -- `/apps/www`: http://localhost:3000 - - The main website. -- `/apps/temp-docs`: http://localhost:3001 - - We are migrating the docs to a Next.js application. -- `/apps/temp-community-forum`: http://localhost:3002 - - pulls all our github discussions into a nextjs site. Temporary/POC -- `/apps/temp-community-tutorials`: http://localhost:3003 - - pulls all our DEV articles (which community members can write) into a nextjs site. Temporary/POC +Site | Directory | Description | Local development server +---- | --------- | ----------- | ------------------------ +[supabase.com](https://supabase.com) | `/apps/www` | The main website | http://localhost:3000 +[supabase.com/docs](https://supabase.com/docs) | `apps/reference` | Guides and Reference documentaion | http://localhost:3010/docs +[POC] Community forum | `/apps/temp-community-forum` | GitHub Discussions in a Next.js site | http://localhost:3002 +[POC] DEV articles site | `/apps/temp-community-tutorials` | A Next.js site for our DEV articles (which community members can write) | http://localhost:3003 ### Shared components @@ -194,6 +193,7 @@ The monorepo has a set of shared components under `/packages`: - `/packages/common`: Common React code, shared between all sites. - `/packages/config`: All shared config +- `/packages/spec`: Generates documentation using spec files. - `/packages/tsconfig`: Shared Typescript settings ### Installing packages @@ -213,18 +213,8 @@ You do not need to install `devDependencies` in each workspace. These can all be `npm run dev` -## Common Tasks +--- -### Adding Redirects +## Community channels -To add a redirect, simple create a new entry in the [`next.config.js`](https://github.com/supabase/supabase/blob/master/apps/www/next.config.js) file in our main site. - -## Finally - -After making your changes to the file(s) you'd like to update, it's time to open a pull request. Once you submit your pull request, others from the Supabase team/community will review it with you. - -Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors) - -## Community Channels - -Stuck somewhere? Have any questions? please join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help! +Stuck somewhere? Have any questions? Join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help! diff --git a/README.md b/README.md index d251a2bf678..446e3316709 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- - + +

--- @@ -45,7 +45,7 @@ To see how to Contribute, visit [Getting Started](./DEVELOPERS.md) We are currently in Public Beta. Watch "releases" of this repo to get notified of major updates. -Watch this repo +Watch this repo --- @@ -58,7 +58,7 @@ Supabase is a combination of open source tools. We’re building the features of Supabase is a [hosted platform](https://app.supabase.com). You can sign up and start using Supabase without installing anything. You can also [self-host](https://supabase.com/docs/guides/hosting/overview) and [develop locally](https://supabase.com/docs/guides/local-development). -![Architecture](https://supabase.com/docs/assets/images/supabase-architecture-9050a7317e9ec7efb7807f5194122e48.png) +![Architecture](https://user-images.githubusercontent.com/70828596/187547862-ffa9d058-0c3a-4851-a3e7-92ccfca4b596.png) - [PostgreSQL](https://www.postgresql.org/) is an object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance. - [Realtime](https://github.com/supabase/realtime) is an Elixir server that allows you to listen to PostgreSQL inserts, updates, and deletes using websockets. Realtime polls Postgres' built-in replication functionality for database changes, converts changes to JSON, then broadcasts the JSON over websockets to authorized clients. @@ -76,7 +76,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i Language Client - Feature-Clients (bundled in Supabase client) + Feature-Clients (bundled in Supabase client) @@ -85,6 +85,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i GoTrue Realtime Storage + Functions - ⚡️ Official ⚡️ + ⚡️ Official ⚡️ JavaScript (TypeScript) supabase-js @@ -105,8 +106,9 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-js realtime-js storage-js + functions-js - 💚 Community 💚 + 💚 Community 💚 C# supabase-csharp @@ -114,6 +116,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-csharp realtime-csharp storage-csharp + functions-csharp Dart (Flutter) @@ -122,6 +125,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-dart realtime-dart storage-dart + functions-dart Go @@ -129,6 +133,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i postgrest-go - - + storage-go - @@ -138,6 +143,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-java - - + - Kotlin @@ -146,6 +152,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-kt - - + - Python @@ -153,7 +160,8 @@ Our approach for client libraries is modular. Each sub-library is a standalone i postgrest-py gotrue-py realtime-py - - + storage-py + functions-py Ruby @@ -162,6 +170,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i - - - + - Rust @@ -170,6 +179,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i - - - + - Swift @@ -178,6 +188,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i gotrue-swift realtime-swift storage-swift + - @@ -189,10 +200,12 @@ Our approach for client libraries is modular. Each sub-library is a standalone i - [Arabic | العربية](/i18n/README.ar.md) - [Albanian / Shqip](/i18n/README.sq.md) - [Bangla / বাংলা](/i18n/README.bn.md) +- [Bulgarian / Български](/i18n/README.bg.md) - [Catalan / Català](/i18n/README.ca.md) - [Danish / Dansk](/i18n/README.da.md) - [Dutch / Nederlands](/i18n/README.nl.md) - [English](https://github.com/supabase/supabase) +- [Finnish / Suomalainen](/i18n/README.fi.md) - [French / Français](/i18n/README.fr.md) - [German / Deutsch](/i18n/README.de.md) - [Greek / Ελληνικά](/i18n/README.gr.md) diff --git a/SECURITY.md b/SECURITY.md index 247288302c4..b257313bf5d 120000 --- a/SECURITY.md +++ b/SECURITY.md @@ -1 +1 @@ -web/static/.well-known/security.txt \ No newline at end of file +apps/reference/static/.well-known/security.txt diff --git a/about/docs/careers/_snippets/about.mdx b/about/docs/careers/_snippets/about.mdx index e5a186ffad5..d86aaefe294 100644 --- a/about/docs/careers/_snippets/about.mdx +++ b/about/docs/careers/_snippets/about.mdx @@ -1,3 +1,3 @@ -Supabase is an open source Firebase alternative. We're backed by Y Combinator, Mozilla, Coatue, and a bunch of [amazing developers](https://supabase.com/blog/2021/03/25/angels-of-supabase). +Supabase is an open source Firebase alternative. We're backed by Y Combinator, Mozilla, Coatue, and a bunch of [amazing developers](https://supabase.com/blog/angels-of-supabase). Supabase is a platform which makes it incredibly easy to build _and_ scale your projects. diff --git a/about/docs/handbook/supasquad.mdx b/about/docs/handbook/supasquad.mdx index 58eaa06448f..28ac655629a 100644 --- a/about/docs/handbook/supasquad.mdx +++ b/about/docs/handbook/supasquad.mdx @@ -46,14 +46,12 @@ Help us maintain the community guidelines in our GitHub and Community-led commun - Access to a Supabase Discord channel providing direct communication with the team, Discord badges, and elevated privileges. - Special AMA sessions with members of the Supabase team. -- Monthly DevRel committee call with industry-leading Developer Advocates (many of whom are [angel investors](https://supabase.com/blog/2021/03/25/angels-of-supabase)), where you can learn from the best. +- Monthly DevRel committee call with industry-leading Developer Advocates (many of whom are [angel investors](https://supabase.com/blog/angels-of-supabase)), where you can learn from the best. - We'll help you build your audience by promoting content via the Supabase social channels. -- Featured profile on Supabase website. - Early access to new features (and the opportunity to provide feedback to the team!). - Free credits that you can use for Squad efforts. - Direct access to members of the Supabase team for questions, suggestions, etc. - Help shape the future of the program. -- Invited to the [SupaSquad GitHub Org](https://github.com/supasquad) to collaborate with the other squad members. - Exclusive Supabase Team swag drops usually exclusively reserved to the Supabase core team. ## How to join diff --git a/about/package-lock.json b/about/package-lock.json index 6a564d42335..546a81ba1e7 100644 --- a/about/package-lock.json +++ b/about/package-lock.json @@ -1753,6 +1753,49 @@ "@hapi/hoek": "^9.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@kiwicopple/prism-react-renderer": { "version": "git+ssh://git@github.com/kiwicopple/prism-react-renderer.git#4a09100a587bce2d94d7ac8ed3564a61c6e70781", "from": "@kiwicopple/prism-react-renderer@github:kiwicopple/prism-react-renderer", @@ -12865,9 +12908,9 @@ "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" }, "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -12902,6 +12945,11 @@ "webpack-sources": "^1.4.3" }, "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -12996,21 +13044,24 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, - "terser": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", - "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } + "source-map-support": "~0.5.20" } } } diff --git a/about/src/css/custom.css b/about/src/css/custom.css index 7d12b14f42d..01b3ef754fe 100755 --- a/about/src/css/custom.css +++ b/about/src/css/custom.css @@ -1,5 +1,5 @@ -/* - Font import +/* + Font import */ @import url('https://rsms.me/inter/inter.css'); @@ -30,7 +30,7 @@ :root[data-theme='dark'] { /* See theme-specific "--custom" vars below */ - /* + /* Customization here for both Light and Dark themes */ --custom-font-base: 'Inter', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen', @@ -71,7 +71,7 @@ --custom-shadow-tl: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1); --custom-shadow-xl: 0 30px 60px 0 rgba(0, 0, 0, 0.1); - /* + /* Infirma overrides with customization */ /* Colors */ @@ -542,8 +542,8 @@ a.card:hover { line-height: calc(var(--ifm-spacing-vertical) * 1); } -/* - Link chevrons +/* + Link chevrons */ .menu .menu__link.menu__link--sublist::after { background-image: url('data:image/svg+xml;utf8,'); diff --git a/apps/reference/.gitignore b/apps/reference/.gitignore new file mode 100644 index 00000000000..6327667b400 --- /dev/null +++ b/apps/reference/.gitignore @@ -0,0 +1,22 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +**/*/generated \ No newline at end of file diff --git a/apps/reference/.prettierignore b/apps/reference/.prettierignore new file mode 100644 index 00000000000..b2d6de30624 --- /dev/null +++ b/apps/reference/.prettierignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/apps/reference/README.md b/apps/reference/README.md new file mode 100644 index 00000000000..4f3b8c0389f --- /dev/null +++ b/apps/reference/README.md @@ -0,0 +1,45 @@ +# Reference Docs + +Supabase Reference Docs + +## Maintainers + +If you are a maintainer of any tools in the Supabase ecosystem, you can use this site to provide documentation for the tools & libraries that you maintain. + +## Types of docs + +There are many types of docs: + +1. Guides: teach developers how to use a product. "I have XX problem, how do I solve it?" +2. Tutorials: walk-throughs, have a large outcome. "Build a React application with Supabase". +3. Explanations: teach developers about a broad topic. "What is a database?" +4. Reference: technical descriptions of tools and how to use them. "What errors does the API return?" + +In these docs, you should focus only on the fourth type: "Reference Docs". + +## Versioning + +All tools have versioned docs, which are kept in separate folders. For example, the CLI has the following folders and files: + +- `cli`: the "next" release. +- `cli_spec`: contains the DocSpec for the "next" release (see below). +- `cli_versioned_docs`: a version of the documentation for every release (including the most current version). +- `cli_versioned_sidebars`: a version of the sidebar for every release (including the most current version). + +When you release a new version of a tool, you should also release a new version of the docs. You can do this via the command line. For example, if you just released the CLI version `1.0.1`: + +``` +npm run cli:version 1.0.1 +``` + +## DocSpec + +We use documentation specifications which can be used to generate human-readable docs. + +- OpenAPI: for documenting API endpoints. +- SDKSpec (custom to Supabase): for SDKs and client libraries. +- ConfigSpec (custom to Supabase): for configuration options. +- CLISpec (custom to Supabase): for CLI commands and usage. + +The benefit of using custom specifications is that we can generate many other types from a strict schema (eg, HTML and manpages). +It also means that we can switch any documentation system we want. On this site we use Docusaurus, but in Supabase's official website we use a custom React site and expose only a subset of the available API for each tool. diff --git a/apps/reference/_api/intro.md b/apps/reference/_api/intro.md new file mode 100644 index 00000000000..8f9bd942142 --- /dev/null +++ b/apps/reference/_api/intro.md @@ -0,0 +1,37 @@ +--- +slug: / +sidebar_position: 1 +sidebar_label: Supabase API +--- + +# Supabase API + +The Supabase API allows you to manage your projects programmatically. + +## Status + +The Supabase API is in `beta`. It is usable in it's current state, but it's likely that there will be breaking changes. + +## Authentication + +All API requests require a Supabase Personal token to be included in the Authorization header: `Authorization Bearer + + + + + + + + +## Organizations {#organizations} + +Organization endpoints + + + + + +### List all organizations {#list-all-organizations} + +``` +GET https://api.supabase.com/v1/organizations +``` + + + + + + + + + + + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + } + } +} +``` + + + + + + + + +Unexpected error listing organizations + + + + + + + + + + + +
+ + + + +### Create an organization {#create-an-organization} + +``` +POST https://api.supabase.com/v1/organizations +``` + + + + + + + + + + + +#### Body Parameters + +```json +{ + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + } +} +``` + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + } +} +``` + + + + + + + + +Unexpected error creating an organization + + + + + + + + + + + +
+ + + +## Projects {#projects} + +Project endpoints + + + + + +### List all projects {#list-all-projects} + +``` +GET https://api.supabase.com/v1/projects +``` + + + + + + + + + + + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "created_at": { + "type": "string" + } + }, + "required": [ + "id", + "organization_id", + "name", + "region", + "created_at" + ] + } + } +} +``` + + + + + + + + +
+ + + + +### Create a project {#create-a-project} + +``` +POST https://api.supabase.com/v1/projects +``` + + + + + + + + + + + +#### Body Parameters + +```json +{ + "schema": { + "type": "object", + "properties": { + "db_pass": { + "type": "string" + }, + "name": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "plan": { + "type": "string", + "enum": [ + "free", + "pro" + ] + }, + "region": { + "type": "string", + "enum": [ + "us-east-1", + "us-west-1", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-central-1", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ] + }, + "kps_enabled": { + "type": "boolean" + } + }, + "required": [ + "db_pass", + "name", + "organization_id", + "plan", + "region" + ] + } +} +``` + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "created_at": { + "type": "string" + } + }, + "required": [ + "id", + "organization_id", + "name", + "region", + "created_at" + ] + } +} +``` + + + + + + + + +
+ + + + +### List all functions {#list-all-functions} + +``` +GET https://api.supabase.com/v1/projects/{ref}/functions +``` + + + + +#### Path Parameters + + + + + + + + + + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "enum": [ + "ACTIVE", + "REMOVED", + "THROTTLED" + ], + "type": "string" + }, + "version": { + "type": "number" + }, + "created_at": { + "type": "number" + }, + "updated_at": { + "type": "number" + }, + "verify_jwt": { + "type": "boolean" + } + }, + "required": [ + "id", + "slug", + "name", + "status", + "version", + "created_at", + "updated_at" + ] + } + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to retrieve project's functions + + + + + + + + + + + +
+ + + + +### Create a function {#create-a-function} + +``` +POST https://api.supabase.com/v1/projects/{ref}/functions +``` + + + + +#### Path Parameters + + + + + + + + + + +#### Body Parameters + +```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" + ] + } +} +``` + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "enum": [ + "ACTIVE", + "REMOVED", + "THROTTLED" + ], + "type": "string" + }, + "version": { + "type": "number" + }, + "created_at": { + "type": "number" + }, + "updated_at": { + "type": "number" + }, + "verify_jwt": { + "type": "boolean" + } + }, + "required": [ + "id", + "slug", + "name", + "status", + "version", + "created_at", + "updated_at" + ] + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to create project's function + + + + + + + + + + + +
+ + + + +### Retrieve a function {#retrieve-a-function} + +``` +GET https://api.supabase.com/v1/projects/{ref}/functions/{function_slug} +``` + + + + +#### Path Parameters + + + + + + + + + + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "enum": [ + "ACTIVE", + "REMOVED", + "THROTTLED" + ], + "type": "string" + }, + "version": { + "type": "number" + }, + "created_at": { + "type": "number" + }, + "updated_at": { + "type": "number" + }, + "verify_jwt": { + "type": "boolean" + }, + "body": { + "type": "string" + } + }, + "required": [ + "id", + "slug", + "name", + "status", + "version", + "created_at", + "updated_at" + ] + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to retrieve function with given slug + + + + + + + + + + + +
+ + + + +### Update a function {#update-a-function} + +``` +PATCH https://api.supabase.com/v1/projects/{ref}/functions/{function_slug} +``` + + + + +#### Path Parameters + + + + + + + + + + +#### Body Parameters + +```json +{ + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "body": { + "type": "string" + }, + "verify_jwt": { + "type": "boolean" + } + } + } +} +``` + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "enum": [ + "ACTIVE", + "REMOVED", + "THROTTLED" + ], + "type": "string" + }, + "version": { + "type": "number" + }, + "created_at": { + "type": "number" + }, + "updated_at": { + "type": "number" + }, + "verify_jwt": { + "type": "boolean" + } + }, + "required": [ + "id", + "slug", + "name", + "status", + "version", + "created_at", + "updated_at" + ] + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to update function with given slug + + + + + + + + + + + +
+ + + + +### Delete a function {#delete-a-function} + +``` +DELETE https://api.supabase.com/v1/projects/{ref}/functions/{function_slug} +``` + + + + +#### Path Parameters + + + + + + + + + + + + + +#### Responses + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Failed to delete function with given slug + + + + + + + + + + + +
+ + + + +### List all secrets {#list-all-secrets} + +``` +GET https://api.supabase.com/v1/projects/{ref}/secrets +``` + + + + +#### Path Parameters + + + + + + + + + + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + } + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to retrieve project's secrets + + + + + + + + + + + +
+ + + + +### Bulk create secrets {#bulk-create-secrets} + +``` +POST https://api.supabase.com/v1/projects/{ref}/secrets +``` + + + + +#### Path Parameters + + + + + + + + + + +#### Body Parameters + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string", + "pattern": "/^(?!SUPABASE_).*/" + } + }, + "required": [ + "name", + "value" + ] + } + } +} +``` + + + + +#### Responses + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Failed to create project's secrets + + + + + + + + + + + +
+ + + + +### Bulk delete secrets {#bulk-delete-secrets} + +``` +DELETE https://api.supabase.com/v1/projects/{ref}/secrets +``` + + + + +#### Path Parameters + + + + + + + + + + +#### Body Parameters + +```json +{ + "schema": { + "type": "array", + "items": { + "type": "string" + } + } +} +``` + + + + +#### Responses + + + + + + + + + + +```json +{ + "schema": { + "type": "object" + } +} +``` + + + + + + + + + + + + + + + + + + + + +Failed to delete secrets with given names + + + + + + + + + + + +
+ diff --git a/web/docs/gotrue/client/.gitkeep b/apps/reference/_api_versioned_docs/.gitkeep similarity index 100% rename from web/docs/gotrue/client/.gitkeep rename to apps/reference/_api_versioned_docs/.gitkeep diff --git a/web/docs/reference/cli/.gitkeep b/apps/reference/_api_versioned_sidebars/.gitkeep similarity index 100% rename from web/docs/reference/cli/.gitkeep rename to apps/reference/_api_versioned_sidebars/.gitkeep diff --git a/web/src/data/showcase.json b/apps/reference/_api_versions.json similarity index 100% rename from web/src/data/showcase.json rename to apps/reference/_api_versions.json diff --git a/apps/reference/_auth_helpers/intro.md b/apps/reference/_auth_helpers/intro.md new file mode 100644 index 00000000000..51239a87b48 --- /dev/null +++ b/apps/reference/_auth_helpers/intro.md @@ -0,0 +1,17 @@ +--- +slug: / +sidebar_label: Auth Helpers +--- + +# Auth Helpers + +A collection of framework specific Auth utilities for working with Supabase. + +## Status + +The Auth Helpers are in `beta`. They are usable in their current state, but it's likely that there will be breaking changes. + +## Additional Links + +- [Source code](https://github.com/supabase/auth-helpers) +- [Known bugs and issues](https://github.com/supabase/auth-helpers/issues) diff --git a/apps/reference/_auth_helpers/next-js.md b/apps/reference/_auth_helpers/next-js.md new file mode 100644 index 00000000000..7ae2a9873cc --- /dev/null +++ b/apps/reference/_auth_helpers/next-js.md @@ -0,0 +1,315 @@ +--- +id: next-js +slug: next-js +sidebar_label: With Next.js +--- + +# Supabase Auth with Next.js + +This submodule provides convenience helpers for implementing user authentication in Next.js applications. + +## Installation + +Using [npm](https://npmjs.org): + +```sh +npm install @supabase/auth-helpers-nextjs + +# Main components and hooks for React based frameworks (optional) +npm install @supabase/auth-helpers-react +``` + +Using [yarn](https://yarnpkg.com/): + +```sh +yarn add @supabase/auth-helpers-nextjs + +# Main components and hooks for React based frameworks (optional) +yarn add @supabase/auth-helpers-react +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` + +- Next.js: `>=10` + +## Getting Started + +### Configuration + +Set up the following env vars. For local development you can set them in a `.env.local` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/nextjs/.env.local.example). + +```bash +# Find these in your Supabase project settings > API +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key +``` + +### Basic Setup + +- Create an `auth` directory under the `/pages/api/` directory. + +- Create a `[...supabase].js` file under the newly created `auth` directory. + +The path to your dynamic API route file would be `/pages/api/auth/[...supabase].js`. Populate that file as follows: + +```js +import { handleAuth } from '@supabase/auth-helpers-nextjs' + +export default handleAuth({ logout: { returnTo: '/' } }) +``` + +Executing `handleAuth()` creates the following route handlers under the hood that perform different parts of the authentication flow: + +- `/api/auth/callback`: The `UserProvider` forwards the session details here every time `onAuthStateChange` fires on the client side. This is needed to set up the cookies for your application so that SSR works seamlessly. + +- `/api/auth/user`: You can fetch user profile information in JSON format. + +- `/api/auth/logout`: Your Next.js application logs out the user. You can optionally pass a `returnTo` parameter to return to a custom relative URL after logout, eg `/api/auth/logout?returnTo=/login`. This will overwrite the logout `returnTo` option specified `handleAuth()` + +Wrap your `pages/_app.js` component with the `UserProvider` component: + +```jsx +// pages/_app.js +import React from 'react' +import { UserProvider } from '@supabase/auth-helpers-react' +import { supabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function App({ Component, pageProps }) { + return ( + + + + ) +} +``` + +You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined. + +## Client-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `# @supabase/auth-helpers-nextjs` and only run your query once the user is defined client-side in the `useUser()` hook: + +```js +import { Auth } from '@supabase/ui' +import { useUser } from '@supabase/auth-helpers-react' +import { supabaseClient } from '@supabase/auth-helpers-nextjs' +import { useEffect, useState } from 'react' + +const LoginPage = () => { + const { user, error } = useUser() + const [data, setData] = useState() + + useEffect(() => { + async function loadData() { + const { data } = await supabaseClient.from('test').select('*') + setData(data) + } + // Only run query once user is logged in. + if (user) loadData() + }, [user]) + + if (!user) + return ( + <> + {error &&

{error.message}

} + + + ) + + return ( + <> + +

user:

+
{JSON.stringify(user, null, 2)}
+

client-side data fetching with RLS

+
{JSON.stringify(data, null, 2)}
+ + ) +} + +export default LoginPage +``` + +### Server-side rendering (SSR) - withPageAuth + +If you wrap your `getServerSideProps` with `withPageAuth` your props object will be augmented with the user object. + +```js +// pages/profile.js +import { withPageAuth } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }) { + return
Hello {user.name}
+} + +export const getServerSideProps = withPageAuth({ redirectTo: '/login' }) +``` + +If there is no authenticated user, they will be redirect to your home page, unless you specify the `redirectTo` option. + +You can pass in your own `getServerSideProps` method, the props returned from this will be merged with the +user props. You can also access the user session data by calling `getUser` inside of this method, eg: + +```js +// pages/protected-page.js +import { withPageAuth, getUser } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, customProp }) { + return
Protected content
+} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/foo', + async getServerSideProps(ctx) { + // Access the user object + const { user, accessToken } = await getUser(ctx) + return { props: { email: user?.email } } + }, +}) +``` + +### Server-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to inject the request context into the supabase client: + +```js +import { + User, + withPageAuth, + supabaseServerClient, +} from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ + user, + data, +}: { + user: User, + data: any, +}) { + return ( + <> +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/', + async getServerSideProps(ctx) { + // Run queries with RLS on the server + const { data } = await supabaseServerClient(ctx).from('test').select('*') + return { props: { data } } + }, +}) +``` + +### Server-side data fetching to OAuth APIs using `provider_token` + +When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted as an HTTPOnly cookie upon logging in to enabled usage on the server side. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. In the following example, we fetch the user's full profile from the third-party API during SSR using their id and auth token: + +```js +import { User, withPageAuth, getUser } from '@supabase/auth-helpers-nextjs' + +interface Profile { + /* ... */ +} + +export default function ProtectedPage({ + user, + data, +}: { + user: User, + profile: Profile, +}) { + return
Protected content
+} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/', + async getServerSideProps(ctx) { + // Retrieve provider_token from cookies + const provider_token = ctx.req.cookies['sb-provider-token'] + // Get logged in user's third-party id from metadata + const { user } = await getUser(ctx) + const userId = user?.user_metadata.provider_id + const profile: Profile = await ( + await fetch(`https://api.example.com/users/${userId}`, { + method: 'GET', + headers: { + Authorization: `Bearer ${provider_token}`, + }, + }) + ).json() + return { props: { profile } } + }, +}) +``` + +## Protecting API routes + +Wrap an API Route to check that the user has a valid session. If they're not logged in the handler will return a +401 Unauthorized. + +```js +// pages/api/protected-route.js +import { + withApiAuth, + supabaseServerClient, +} from '@supabase/auth-helpers-nextjs' + +export default withApiAuth(async function ProtectedRoute(req, res) { + // Run queries with RLS on the server + const { data } = await supabaseServerClient({ req, res }) + .from('test') + .select('*') + res.json(data) +}) +``` + +If you visit `/api/protected-route` without a valid session cookie, you will get a 401 response. + +## Protecting routes with [Nextjs Middleware](https://nextjs.org/docs/middleware) + +As an alternative to protecting individual pages using `getServerSideProps` with `withPageAuth`, `withMiddlewareAuth` can be used from inside a `_middleware` file to protect an entire directory. In the following example, all requests to `/protected/*` will check whether a user is signed in, if successful the request will be forwarded to the destination route, otherwise the user will be redirected to `/login` (defaults to: `/`) with a 307 Temporary Redirect response status: + +```ts +// pages/protected/_middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/middleware' + +export const middleware = withMiddlewareAuth({ redirectTo: '/login' }) +``` + +It is also possible to add finer granularity based on the user logged in. I.e. you can specify a promise to determine if a specific user has permission or not. + +```ts +// pages/protected/_middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/dist/middleware' + +export const middleware = withMiddlewareAuth({ + redirectTo: '/login', + authGuard: { + isPermitted: async (user) => user.email?.endsWith('@example.com') ?? false, + redirectTo: '/insufficient-permissions', + }, +}) +``` + +## Migrating from @supabase/supabase-auth-helpers to @supabase/auth-helpers + +This is a step by step guide on migrating away from the `@supabase/supabase-auth-helpers` to the newly released `@supabase/auth-helpers`. + +1. Install `@supabase/supabase-js`, `@supabase/auth-helpers-nextjs` and `@supabase/auth-helpers-react` libraries from npm. +2. Replace all imports of `@supabase/supabase-auth-helpers/nextjs` in your project with `@supabase/auth-helpers-nextjs`. +3. Replace all imports of `@supabase/supabase-auth-helpers/react` in your project with `@supabase/auth-helpers-react`. +4. Replace all instances of `withAuthRequired` in any of your NextJS pages with `withPageAuth`. +5. Replace all instances of `withAuthRequired` in any of your NextJS API endpoints with `withApiAuth`. +6. Uninstall `@supabase/supabase-auth-helpers`. diff --git a/apps/reference/_auth_helpers/svelte-kit.md b/apps/reference/_auth_helpers/svelte-kit.md new file mode 100644 index 00000000000..46980643cb9 --- /dev/null +++ b/apps/reference/_auth_helpers/svelte-kit.md @@ -0,0 +1,303 @@ +--- +id: sveltekit +slug: sveltekit +sidebar_label: With SvelteKit +--- + +# Supabase Auth with SvelteKit + +This submodule provides convenience helpers for implementing user authentication in [SvelteKit](https://kit.svelte.dev/) applications. + +## Installation + +Using [npm](https://npmjs.org): + +```sh +npm install @supabase/auth-helpers-sveltekit + +# Main component for Svelte based frameworks (optional but recommended) +npm install @supabase/auth-helpers-svelte +``` + +Using [yarn](https://yarnpkg.com/): + +```sh +yarn add @supabase/auth-helpers-sveltekit + +# Main component for Svelte based frameworks (optional but recommended) +yarn add @supabase/auth-helpers-svelte +``` + +This library supports the following tooling versions: + +- Node.js: `^16.15.0` + +## Getting Started + +### Configuration + +Set up the fillowing env vars. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/sveltekit/.env.example). + +```bash +# Find these in your Supabase project settings > API +VITE_SUPABASE_URL=https://your-project.supabase.co +VITE_SUPABASE_ANON_KEY=your-anon-key +``` + +### SupabaseClient and SupaAuthHelper component setup + +We will start off by creating a `db.ts` file inside of our `src/lib` directory. Now lets instantiate our `supabaseClient` by using our `createSupabaseClient` function from the `@supabase/auth-helpers-sveltekit` library. + +```ts +// src/lib/db.ts +import { createSupabaseClient } from '@supabase/auth-helpers-sveltekit' + +const { supabaseClient } = createSupabaseClient( + import.meta.env.VITE_SUPABASE_URL as string, + import.meta.env.VITE_SUPABASE_ANON_KEY as string +) + +export { supabaseClient } +``` + +Edit your `__layout.svelte` file and add import the `SupaAuthHelper` component, the `supabaseClient` we just instantiated and the `session` store. + +```html +// src/routes/__layout.svelte + + + + + +``` + +### Hooks setup + +Our `hooks.ts` file is where the heavy lifting of this library happens, we need to import our function to handle the sign in, signing out and cookie creation phase. we can import all the hooks using `handleAuth` function and destructure its returned data. + +```ts +// src/hooks.ts +import { handleAuth } from '@supabase/auth-helpers-sveltekit' +import type { GetSession, Handle } from '@sveltejs/kit' +import { sequence } from '@sveltejs/kit/hooks' + +export const handle: Handle = sequence(...handleAuth()) + +export const getSession: GetSession = async (event) => { + const { user, accessToken, error } = event.locals + return { + user, + accessToken, + error, + } +} +``` + +These will create the handlers under the hood that perform different parts of the authentication flow: + +- `/api/auth/callback`: The `UserHelper` forwards the session details here every time `onAuthStateChange` fires on the client side. This is needed to set up the cookies for your application so that SSR works seamlessly. +- `/api/auth/user`: You can fetch user profile information in JSON format. +- `/api/auth/logout`: You can logout the user. + +### Typings + +In order to get the most out of TypeScript and its intellisense, you should import our types into the `app.d.ts` type definition file that comes with your SvelteKit project. + +```ts +// src/app.d.ts +/// +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare namespace App { + interface UserSession { + user: import('@supabase/supabase-js').User + accessToken?: string + } + interface Locals extends UserSession { + error: import('@supabase/supabase-js').ApiError + } + + interface Session extends UserSession {} // interface Platform {} // interface Stuff {} +} +``` + +### Signing out + +This library has provided a dedicated endpoint for you to use to sign a user out. This endpoint will sign the user out of the Gotrue server, clear the cookies that were set when the user logged in and redirect the user to a configurable path. + +The logout handler endpoint is `/api/auth/logout`, this will take a `GET` request which means it can be used as the href for a normal `a` tag in your html. + +```html +Sign out +``` + +### Logout handler configuration + +In your `src/hooks.ts` file the logout handler is already setup and you can configure the redirect path from here. + +> By default the redirect path after logging out will be `/`. + +```ts +export const handle = sequence( + ...handleAuth({ + logout: { returnTo: '/auth/signin' }, + }) +) +``` + +### Basic Setup + +You can now determine if a user is authenticated on the client-side by checking that the `user` object returned by the `$session` store is defined. + +```html +// example + + +{#if !$session.user} +

I am not logged in

+{:else} +

Welcome {$session.user.email}

+

I am logged in!

+{/if} +``` + +## Client-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `@supabase/auth-helpers-sveltekit` and only run your query once the user is defined client-side in the `$session`: + +```html + + +{#if !$session.user} + {#if $error} +

{$error.message}

+ {/if} +

{$isLoading ? `Loading...` : `Loaded!`}

+ +{:else} + Sign out +

user:

+
{JSON.stringify($session.user, null, 2)}
+

client-side data fetching with RLS

+
{JSON.stringify(loadedData, null, 2)}
+{/if} +``` + +### Server-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to inject the request context into the supabase client: + +```html + + + +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+``` + +```ts +// src/routes/profile.ts +import { + supabaseServerClient, + withApiAuth, +} from '@supabase/auth-helpers-sveltekit' +import type { RequestHandler } from './__types/profile' + +interface TestTable { + id: string + created_at: string +} + +interface GetOutput { + user: User + data: TestTable[] +} + +export const GET: RequestHandler = async ({ locals }) => + withApiAuth( + { + redirectTo: '/', + user: locals.user, + }, + async () => { + const { data } = await supabaseServerClient(session.accessToken) + .from('test') + .select('*') + + return { + body: { + user: locals.user, + data, + }, + } + } + ) +``` + +## Protecting API routes + +Wrap an API Route to check that the user has a valid session. If they're not logged in the handler will return a +303 and redirect header. + +```ts +// src/routes/api/protected-route.ts +import { + supabaseServerClient, + withApiAuth, +} from '@supabase/auth-helpers-sveltekit' +import type { RequestHandler } from './__types/protected-route' + +interface TestTable { + id: string + created_at: string +} + +interface GetOutput { + data: TestTable[] +} + +export const GET: RequestHandler = async ({ locals, request }) => + withApiAuth({ user: locals.user }, async () => { + // Run queries with RLS on the server + const { data } = await supabaseServerClient(request) + .from('test') + .select('*') + + return { + status: 200, + body: { data }, + } + }) +``` + +If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response. diff --git a/web/docs/reference/dart/.gitkeep b/apps/reference/_cli/generated/.gitkeep similarity index 100% rename from web/docs/reference/dart/.gitkeep rename to apps/reference/_cli/generated/.gitkeep diff --git a/apps/reference/_cli/intro.mdx b/apps/reference/_cli/intro.mdx new file mode 100644 index 00000000000..1615aa7ae28 --- /dev/null +++ b/apps/reference/_cli/intro.mdx @@ -0,0 +1,26 @@ +--- +id: intro +slug: / +sidebar_position: 1 +sidebar_label: Supabase CLI +hide_table_of_contents: true +--- + +# Supabase CLI + +The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform. +The CLI is still under development, but it contains all the functionality for working with your Supabase projects and the Supabase Platform. + +- Run Supabase locally: [`supabase start`](https://supabase.com/docs/reference/cli/usage#supabase-start) +- Manage database migrations: [`supabase migration`](https://supabase.com/docs/reference/cli/usage#supabase-migration) +- CI/CD for releasing to production: [`supabase db push`](https://supabase.com/docs/reference/cli/usage#supabase-db-push) +- Manage your Supabase projects: [`supabase projects`](https://supabase.com/docs/reference/cli/usage#supabase-projects) +- Generate types directly from your database schema: [`supabase gen types`](https://supabase.com/docs/reference/cli/usage#supabase-gen) + +## Additional Links + +- [Install the Supabase CLI](/docs/guides/cli) +- [Source code](https://github.com/supabase/cli) +- [Known bugs and issues](https://github.com/supabase/cli/issues) +- [Supabase CLI v1 and Admin API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta) +- [The CLI team announcing CLI V1 and Admin API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28) diff --git a/apps/reference/_cli/release-notes.mdx b/apps/reference/_cli/release-notes.mdx new file mode 100644 index 00000000000..e10337f8d04 --- /dev/null +++ b/apps/reference/_cli/release-notes.mdx @@ -0,0 +1,7 @@ +--- +id: release-notes +--- + +# Release Notes + +All release notes can be found in the [GitHub Releases page](https://github.com/supabase/cli/releases). diff --git a/web/docs/reference/javascript/.gitkeep b/apps/reference/_cli_versioned_docs/.gitkeep similarity index 100% rename from web/docs/reference/javascript/.gitkeep rename to apps/reference/_cli_versioned_docs/.gitkeep diff --git a/web/spec/listen-to-database-changes.md b/apps/reference/_cli_versioned_sidebars/.gitkeep similarity index 100% rename from web/spec/listen-to-database-changes.md rename to apps/reference/_cli_versioned_sidebars/.gitkeep diff --git a/apps/reference/_cli_versions.json b/apps/reference/_cli_versions.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/apps/reference/_cli_versions.json @@ -0,0 +1 @@ +[] diff --git a/apps/reference/_gotrue/config.mdx b/apps/reference/_gotrue/config.mdx new file mode 100644 index 00000000000..9a00a5a380e --- /dev/null +++ b/apps/reference/_gotrue/config.mdx @@ -0,0 +1,35 @@ +--- +id: config +slug: /config +title: Configuration +toc_max_heading_level: 3 +--- + + + +A `config.toml` file is generated after running `supabase init`. + +This file is located in the `supabase` folder under `supabase/config.toml`. + + + + + + +## General {#general} + + + +### `project_id` {#project_id} + +A string used to distinguish different Supabase projects on the same host. Defaults to the working directory name when running `supabase init`. + + +
    +
  • Required: true
  • +
  • Default: None
  • +
+ +
+ + diff --git a/apps/reference/_gotrue/intro.mdx b/apps/reference/_gotrue/intro.mdx new file mode 100644 index 00000000000..cb9a386f235 --- /dev/null +++ b/apps/reference/_gotrue/intro.mdx @@ -0,0 +1,22 @@ +--- +slug: / +sidebar_position: 1 +sidebar_label: Auth Server +--- + +# Supabase Auth Server + +The Supabase Auth Server (GoTrue) is a JSON Web Token (JWT)-based API for managing users and issuing access tokens. + +GoTrue is an open-source API written in Golang, that acts as a self-standing API service for handling user registration and authentication for JAM projects. It's based on OAuth2 and JWT and handles user signup, authentication, and custom user data. + +## Client libraries + +- [JavaScript](https://github.com/supabase/gotrue-js) +- [Dart](https://github.com/supabase/gotrue-dart) + +## Additional Links + +- [Source Code](https://github.com/supabase/gotrue) +- [Known bugs and issues](https://github.com/supabase/gotrue/issues) +- [Auth Guides](https://supabase.com/docs/guides/auth) diff --git a/apps/reference/_gotrue/release-notes.mdx b/apps/reference/_gotrue/release-notes.mdx new file mode 100644 index 00000000000..cb164542845 --- /dev/null +++ b/apps/reference/_gotrue/release-notes.mdx @@ -0,0 +1,7 @@ +--- +id: release-notes +--- + +# Release Notes + +All release notes can be found in the [GitHub Releases](https://github.com/supabase/gotrue/releases) page. diff --git a/apps/reference/_gotrue_versioned_docs/.gitkeep b/apps/reference/_gotrue_versioned_docs/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_gotrue_versioned_sidebars/.gitkeep b/apps/reference/_gotrue_versioned_sidebars/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_gotrue_versions.json b/apps/reference/_gotrue_versions.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/apps/reference/_gotrue_versions.json @@ -0,0 +1 @@ +[] diff --git a/apps/reference/_storage/generated/.gitkeep b/apps/reference/_storage/generated/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_storage/intro.mdx b/apps/reference/_storage/intro.mdx new file mode 100644 index 00000000000..4c038f6c7aa --- /dev/null +++ b/apps/reference/_storage/intro.mdx @@ -0,0 +1,28 @@ +--- +slug: / +sidebar_position: 1 +sidebar_label: Storage Server +--- + +# Supabase Storage Server + +An S3 compatible object storage service that integrates with Postgres. + +- Uses Postgres as it's datastore for storing metadata +- Authorization rules are written as Postgres Row Level Security policies +- Integrates with S3 as the storage backend (with more in the pipeline!) +- Extremely lightweight and performant + +Read [this post](https://supabase.com/blog/supabase-storage) on why we decided to build a new object storage service. + +## Client libraries + +- [JavaScript](https://github.com/supabase/storage-js) +- [Dart](https://github.com/supabase/storage-dart) + +## Additional Links + +- [Source Code](https://github.com/supabase/storage-api) +- [Known bugs and issues](https://github.com/supabase/storage-js/issues) +- [Storage Guides](https://supabase.com/docs/guides/storage) +- [OpenAPI Docs](https://supabase.github.io/storage-api/) diff --git a/apps/reference/_storage/release-notes.mdx b/apps/reference/_storage/release-notes.mdx new file mode 100644 index 00000000000..8dad269f0d9 --- /dev/null +++ b/apps/reference/_storage/release-notes.mdx @@ -0,0 +1,7 @@ +--- +id: release-notes +--- + +# Release Notes + +All release notes can be found in the [GitHub Releases](https://github.com/supabase/storage-api/releases) page. diff --git a/apps/reference/_storage_versioned_docs/.gitkeep b/apps/reference/_storage_versioned_docs/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_storage_versioned_sidebars/.gitkeep b/apps/reference/_storage_versioned_sidebars/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_storage_versions.json b/apps/reference/_storage_versions.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/apps/reference/_storage_versions.json @@ -0,0 +1 @@ +[] diff --git a/apps/reference/_supabase_dart/generated/.gitkeep b/apps/reference/_supabase_dart/generated/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_supabase_dart/initializing.mdx b/apps/reference/_supabase_dart/initializing.mdx new file mode 100644 index 00000000000..e779b7e8ac2 --- /dev/null +++ b/apps/reference/_supabase_dart/initializing.mdx @@ -0,0 +1,36 @@ +--- +id: initializing +title: 'Initializing' +slug: initializing +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +## Dart + +You can initialize a new Supabase client using the `SupabaseClient()` method. + +The Supabase client is your entrypoint to the rest of the Supabase functionality +and is the easiest way to interact with everything we offer within the Supabase ecosystem. + +## Flutter + +For `supabase_flutter`, you will be using the static `initialize()` method on `Supabase` class. + +## Examples + +### Dart `SupabaseClient()` + +```dart +final supabase = SupabaseClient('https://xyzcompany.supabase.co', 'public-anon-key'); +``` + +### Flutter `initialize()` + +```dart title="main.dart" +Future main() async { + await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key'); + runApp(MyApp()); +} +``` diff --git a/apps/reference/_supabase_dart/installing.mdx b/apps/reference/_supabase_dart/installing.mdx new file mode 100644 index 00000000000..2ed91c356fd --- /dev/null +++ b/apps/reference/_supabase_dart/installing.mdx @@ -0,0 +1,31 @@ +--- +id: installing +title: 'Installing' +slug: installing +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +## Dart + +Dart libraries are built and supported by the community. + +```bash +dart pub add supabase +``` + +Find the source code on [GitHub](https://github.com/supabase/supabase-dart). + +## Flutter + +For Flutter project, you can use [supabase_flutter](https://github.com/supabase/supabase-flutter). + +```bash +flutter pub add supabase_flutter +``` + +`supabase_flutter` plugin uses `supabase` plugin internally, and it adds some Flutter specific functionality such as handling deeplinks coming back from magic link verifications. +If you are creating a Flutter application, we recommend using `supabase_flutter` instead of `supabase`. + +For the most part `supabase_flutter` shares the same API as `supabase` with few exceptions such as initialization or OAuth sign in. diff --git a/apps/reference/_supabase_dart/intro.mdx b/apps/reference/_supabase_dart/intro.mdx new file mode 100644 index 00000000000..f1f68aea552 --- /dev/null +++ b/apps/reference/_supabase_dart/intro.mdx @@ -0,0 +1,30 @@ +--- +id: intro +slug: / +sidebar_label: Supabase Dart Library +--- + +# Supabase Dart Library + +:::note + +You're viewing the Supabase docs for a developer preview version. + +Refer to the `v0` docs for the previous release. + +::: + +This reference documents every object and method available in Supabase's isomorphic Dart library, `supabase-dart`. + +You can use the `supabase-dart` library to: + +- interact with your Postgres database +- listen to database changes +- invoke Deno Edge Functions +- build login and user management functionality +- manage large files + +## Additional Links + +- Source Code: [github.com/supabase/supabase-dart](https://github.com/supabase/supabase-dart) +- [Known bugs and issues](https://github.com/supabase/supabase-flutter/issues) diff --git a/apps/reference/_supabase_dart_versioned_docs/version-v0/generated/.gitkeep b/apps/reference/_supabase_dart_versioned_docs/version-v0/generated/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_supabase_dart_versioned_docs/version-v0/intro.mdx b/apps/reference/_supabase_dart_versioned_docs/version-v0/intro.mdx new file mode 100644 index 00000000000..29286743efb --- /dev/null +++ b/apps/reference/_supabase_dart_versioned_docs/version-v0/intro.mdx @@ -0,0 +1,22 @@ +--- +id: intro +slug: / +sidebar_label: Supabase Dart Library +--- + +# Supabase Dart Library + +This reference documents every object and method available in Supabase's isomorphic Dart library, `supabase-dart`. + +You can use the `supabase-dart` library to: + +- interact with your Postgres database +- listen to database changes +- invoke Deno Edge Functions +- build login and user management functionality +- manage large files + +## Additional Links + +- Source Code: [github.com/supabase/supabase-dart](https://github.com/supabase/supabase-dart) +- [Known bugs and issues](https://github.com/supabase/supabase-dart/issues) diff --git a/apps/reference/_supabase_dart_versioned_sidebars/version-v0-sidebars.json b/apps/reference/_supabase_dart_versioned_sidebars/version-v0-sidebars.json new file mode 100644 index 00000000000..44acc0181ad --- /dev/null +++ b/apps/reference/_supabase_dart_versioned_sidebars/version-v0-sidebars.json @@ -0,0 +1,120 @@ +{ + "sidebar": [ + { + "type": "category", + "label": "Getting Started", + "items": ["intro", "generated/installing", "generated/initializing"], + "collapsed": true + }, + { + "type": "category", + "label": "Auth", + "items": [ + "generated/auth-signup", + "generated/auth-signin", + "generated/auth-signinwithprovider", + "generated/auth-signout", + "generated/auth-session", + "generated/auth-user", + "generated/auth-update", + "generated/auth-onauthstatechange", + "generated/reset-password-email" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Functions", + "items": ["generated/invoke"], + "collapsed": true + }, + { + "type": "category", + "label": "Database", + "items": [ + "generated/select", + "generated/insert", + "generated/update", + "generated/upsert", + "generated/delete", + "generated/rpc" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Realtime", + "items": [ + "generated/subscribe", + "generated/removesubscription", + "generated/getsubscriptions", + "generated/stream" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Storage", + "items": [ + "generated/storage-createbucket", + "generated/storage-getbucket", + "generated/storage-listbuckets", + "generated/storage-updatebucket", + "generated/storage-deletebucket", + "generated/storage-emptybucket", + "generated/storage-from-upload", + "generated/storage-from-download", + "generated/storage-from-list", + "generated/storage-from-update", + "generated/storage-from-move", + "generated/storage-from-remove", + "generated/storage-from-createsignedurl", + "generated/storage-from-getpublicurl" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Modifiers", + "items": [ + "generated/using-modifiers", + "generated/limit", + "generated/order", + "generated/range", + "generated/single" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Filters", + "items": [ + "generated/using-filters", + "generated/or", + "generated/not", + "generated/match", + "generated/eq", + "generated/neq", + "generated/gt", + "generated/gte", + "generated/lt", + "generated/lte", + "generated/like", + "generated/ilike", + "generated/is_", + "generated/in_", + "generated/contains", + "generated/containedby", + "generated/rangelt", + "generated/rangegt", + "generated/rangegte", + "generated/rangelte", + "generated/rangeadjacent", + "generated/overlaps", + "generated/textsearch", + "generated/filter" + ], + "collapsed": true + } + ] +} diff --git a/apps/reference/_supabase_dart_versions.json b/apps/reference/_supabase_dart_versions.json new file mode 100644 index 00000000000..574c045ecaf --- /dev/null +++ b/apps/reference/_supabase_dart_versions.json @@ -0,0 +1 @@ +["v0"] diff --git a/apps/reference/_supabase_js/generated/.gitkeep b/apps/reference/_supabase_js/generated/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_supabase_js/installing.mdx b/apps/reference/_supabase_js/installing.mdx new file mode 100644 index 00000000000..960bac4e30f --- /dev/null +++ b/apps/reference/_supabase_js/installing.mdx @@ -0,0 +1,37 @@ +--- +id: installing +title: 'Installing' +slug: installing +custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +All JavaScript libraries are built directly by the Supabase team. + +Other languages are built by the community and supported by Supabase. + +## JavaScript + +Via NPM + +```bash +npm install @supabase/supabase-js +``` + +Via Yarn + +```bash +yarn add @supabase/supabase-js +``` + +Find the source code on [GitHub](https://github.com/supabase/supabase-js). + +Or via CDN + +```js + +//or + +``` diff --git a/apps/reference/_supabase_js/intro.md b/apps/reference/_supabase_js/intro.md new file mode 100644 index 00000000000..3d1394ddd95 --- /dev/null +++ b/apps/reference/_supabase_js/intro.md @@ -0,0 +1,33 @@ +--- +slug: / +sidebar_position: 1 +sidebar_label: Supabase JavaScript Library +hide_table_of_contents: true +--- + +# Supabase JavaScript Library + +:::note + +You're viewing the Supabase docs for the next version of our library which is not yet released. + +Refer to the `v1` docs for a stable release. + +::: + +This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`. + +You can use the `supabase-js` library to: + +- interact with your Postgres database +- listen to database changes +- invoke Deno Edge Functions +- build login and user management functionality +- manage large files + +## Additional Links + +- Source Code: [github.com/supabase/supabase-js](https://github.com/supabase/supabase-js) +- TypeDoc: [supabase.github.io/supabase-js](https://supabase.github.io/supabase-js) +- NPM: [npmjs.com/package/@supabase/supabase-js](https://www.npmjs.com/package/@supabase/supabase-js) +- [Known bugs and issues](https://github.com/supabase/supabase-js/issues) diff --git a/apps/reference/_supabase_js/release-notes.md b/apps/reference/_supabase_js/release-notes.md new file mode 100644 index 00000000000..9a242632754 --- /dev/null +++ b/apps/reference/_supabase_js/release-notes.md @@ -0,0 +1,212 @@ +--- +id: release-notes +--- + +# Release Notes + +Supabase.js v2 release notes. + +## 2.0.0 Release Candidate + +Install the latest with `npm install @supabase/supabase-js@rc`. + +### Explicit constructor options + +All client specific options within the constructor are keyed to the library: [PR](https://github.com/supabase/supabase-js/pull/458): + +```jsx +const supabase = createClient(apiURL, apiKey, { + db: { + schema: 'public', + }, + auth: { + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: true, + }, + realtime: { + channels, + endpoint, + }, + global: { + fetch: customFetch, + headers: DEFAULT_HEADERS, + }, +}) +``` + +### Typescript support + +The libraries now support typescript. + +```ts +// v2 - definitions are injected in `createClient()` +import type { Database } from './DatabaseDefinitions' +const supabase = createClient(SUPABASE_URL, ANON_KEY) +const { data } = await supabase.from('messages').select().match({ id: 1 }) + +// v1 -- previously definitions were injected in the `from()` method +supabase.from('messages').select('*') +``` + +Types can be generated via the CLI: + +```bash +supabase start +supabase gen types typescript --local > DatabaseDefinitions.ts +``` + +### Data operations return minimal + +`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default: [PR](https://github.com/supabase/postgrest-js/pull/276). + +Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end, e.g.: + +```sql +const { data, error } = await supabase + .from('my_table') + .delete() + .eq('id', 1) + .select() +``` + +### New ordering defaults + +`.order()` now defaults to Postgres’s default: [PR](https://github.com/supabase/postgrest-js/pull/283). + +Previously `nullsFirst` defaults to `false` , meaning `null`s are ordered last. This is bad for performance if e.g. the column uses an index with `NULLS FIRST` (which is the default direction for indexes). + +### Cookies and localstorage namespace + +Storage key name in the Auth library has changed to include project reference which means that existing websites that had their JWT expiry set to a longer time could find their users logged out with this upgrade. + +```jsx +const defaultStorageKey = `sb-${ + new URL(this.authUrl).hostname.split('.')[0] +}-auth-token` +``` + +### New Auth Types + +Typescript typings have been reworked. `Session` interface now guarantees that it will always have an `access_token`, `refresh_token` and `user` + +```jsx +interface Session { + provider_token?: string | null + access_token: string + expires_in?: number + expires_at?: number + refresh_token: string + token_type: string + user: User +} +``` + +### New Auth methods + +We're removing the `signIn()` method in favor of more explicit function signatures: +`signInWithPassword()`, `signInWithPasswordless()`, and `signInWithOtp()`. + +```ts +// v2 +const { data } = await supabase.auth.signInWithPassword({ + email: 'hello@example', + password: 'pass', +}) +// v1 +const { data } = await supabase.auth.signIn({ + email: 'hello@example', + password: 'pass', +}) +``` + +### New Realtime methods + +There is a new `channel()` method in the Realtime library, which will be used for our Multiplayer updates. + +```ts +supabaseClient + .channel('any_string_you_want') + .on('presence', { event: 'track' }, (payload) => { + console.log(payload) + }) + .subscribe() + +supabaseClient + .channel('any_string_you_want') + .on( + 'postgres_changes', + { + event: 'INSERT', + schema: 'public', + table: 'movies', + }, + (payload) => { + console.log(payload) + } + ) + .subscribe() +``` + +We will deprecate the `.from().on().subscribe()` method previosuly used for listening to postgres changes. + +### Deprecated setAuth() + +Deprecated and removed `setAuth()` . To set a custom `access_token` jwt instead, pass the custom header into the `createClient()` method provided: ([PR](https://github.com/supabase/gotrue-js/pull/340)) + +### All changes + +- `supabase-js` + - `shouldThrowOnError` has been removed until all the client libraries support this option ([PR](https://github.com/supabase/supabase-js/pull/490)). +- `postgrest-js` + - TypeScript typings have been reworked [PR](https://github.com/supabase/postgrest-js/pull/279) + - Use `undefined` instead of `null` for function params, types, etc. (https://github.com/supabase/postgrest-js/pull/278) + - Some features are now obsolete: (https://github.com/supabase/postgrest-js/pull/275) + - filter shorthands (e.g. `cs` vs. `contains`) + - `body` in response (vs. `data`) + - `upsert`ing through the `.insert()` method + - `auth` method on `PostgrestClient` + - client-level `throwOnError` +- `gotrue-js` + - `supabase-js` client allows passing a `storageKey` param which will allow the user to set the key used in local storage for storing the session. By default, this will be namespace-d with the supabase project ref. ([PR](https://github.com/supabase/supabase-js/pull/460)) + - `signIn` method is now split into `signInWithPassword` , `signInWithPasswordless` , `signInWithOAuth` ([PR](https://github.com/supabase/gotrue-js/pull/304)) + - Deprecated and removed `session()` , `user()` in favour of using `getSession()` instead. `getSession()` will always return a valid session if a user is already logged in, meaning no more random logouts. ([PR](https://github.com/supabase/gotrue-js/pull/299)) + - Deprecated and removed setting for `multitab` support because `getSession()` and gotrue’s reuse interval setting takes care of session management across multiple tabs ([PR](https://github.com/supabase/gotrue-js/pull/366)) + - No more throwing of random errors, gotrue-js v2 always returns a custom error type: ([PR](https://github.com/supabase/gotrue-js/pull/341)) + - `AuthSessionMissingError` + - Indicates that a session is expected but missing + - `AuthNoCookieError` + - Indicates that a cookie is expected but missing + - `AuthInvalidCredentialsError` + - Indicates that the incorrect credentials were passed + - Renamed the `api` namespace to `admin` , the `admin` namespace will only contain methods that should only be used in a trusted server-side environment with the service role key + - Moved `resetPasswordForEmail` , `getUser` and `updateUser` to the `GoTrueClient` which means they will be accessible from the `supabase.auth` namespace in `supabase-js` instead of having to do `supabase.auth.api` to access them + - Removed `sendMobileOTP` , `sendMagicLinkEmail` in favor of `signInWithOtp` + - Removed `signInWithEmail`, `signInWithPhone` in favor of `signInWithPassword` + - Removed `signUpWithEmail` , `signUpWithPhone` in favor of `signUp` + - Replaced `update` with `updateUser` +- `storage-js` + - Return types are more strict. Functions types used to indicate that the data returned could be null even if there was no error. We now make use of union types which only mark the data as null if there is an error and vice versa. ([PR](https://github.com/supabase/storage-js/pull/60)) + - The `upload` and `update` function returns the path of the object uploaded as the `path` parameter. Previously the returned value had the bucket name prepended to the path which made it harder to pass the value on to other storage-js methods since all methods take the bucket name and path separately. We also chose to call the returned value `path` instead of `Key` ([PR](https://github.com/supabase/storage-js/pull/75)) + - `getPublicURL` only returns the public URL inside the data object. This keeps it consistent with our other methods of returning only within the data object. No error is returned since this method cannot does not throw an error ([PR](https://github.com/supabase/storage-js/pull/93)) + - signed urls are returned as `signedUrl` instead of `signedURL` in both `createSignedUrl` and `createSignedUrls` ([PR](https://github.com/supabase/storage-js/pull/94)) + - Encodes URLs returned by `createSignedUrl`, `createSignedUrls` and `getPublicUrl` ([PR](https://github.com/supabase/storage-js/pull/86)) + - `createsignedUrl` used to return a url directly and and within the data object. This was inconsistent. Now we always return values only inside the data object across all methods. ([PR](https://www.notion.so/LW5-supabase-js-v2-7b0bfcdf571d4f20b9b7a9308883f24b)) + - `createBucket` returns a data object instead of the name of the bucket directly. ([PR](https://github.com/supabase/storage-js/pull/89)) + - Fixed types for metadata ([PR](https://github.com/supabase/storage-js/pull/90)) + - Better error types make it easier to track down what went wrong quicker. + - `SupabaseStorageClient` is no longer exported. Use `StorageClient` instead. ([PR](https://github.com/supabase/storage-js/pull/92)). +- `realtime-js` + - `RealtimeSubscription` class no longer exists and replaced by `RealtimeChannel`. + - `RealtimeClient`'s `disconnect` method now returns type of `void` . It used to return type of `Promise<{ error: Error | null; data: boolean }`. + - Removed `removeAllSubscriptions` and `removeSubscription` methods from `SupabaseClient` class. + - Removed `SupabaseRealtimeClient` class. + - Removed `SupabaseQueryBuilder` class. + - Removed `SupabaseEventTypes` type. + - Thinking about renaming this to something like `RealtimePostgresChangeEvents` and moving it to `realtime-js` v2. + - Removed `.from(’table’).on(’INSERT’, () ⇒ {}).subscribe()` in favor of new Realtime client API. +- `functions-js` + - supabase-js v1 only threw an error if the fetch call itself threw an error (network errors, etc) and not if the function returned HTTP errors like 400s or 500s. We have changed this behaviour to return an error if your function throws an error. + - We have introduced new error types to distinguish between different kinds of errors. A `FunctionsHttpError` error is returned if your function throws an error, `FunctionsRelayError` if the Supabase Relay has an error processing your function and `FunctionsFetchError` if there is a network error in calling your function. + - The correct content-type headers are automatically attached when sending the request if you don’t pass in a `Content-Type` header and pass in an argument to your function. We automatically attach the content type for `Blob`, `ArrayBuffer`, `File`, `FormData` ,`String` . If it doesn’t match any of these we assume the payload is `json` , we serialise the payload as JSON and attach the content type as `application/json`. + - `responseType` does not need to be explicitly passed in. We parse the response based on the `Content-Type` response header sent by the function. We support parsing the responses as `text`, `json`, `blob`, `form-data` and are parsed as `text` by default. diff --git a/apps/reference/_supabase_js/working-with-types.md b/apps/reference/_supabase_js/working-with-types.md new file mode 100644 index 00000000000..90314b8fa92 --- /dev/null +++ b/apps/reference/_supabase_js/working-with-types.md @@ -0,0 +1,84 @@ +--- +id: typescript-support +--- + +# Typescript Support + +`supabase-js` supports Typescript. + +## Generating types + +You can use our CLI to generate types: + +```bash +supabase start +supabase gen types typescript --local > lib/database.types.ts +``` + +These types are generated directly from your database. Given a table `public.movies`, the definition will provide the following data: + +```ts +interface Database { + public: { + Tables: { + movies: { + Row: {} // The data expected to be returned from a "select" statement. + Insert: {} // The data expected passed to an "insert" statement. + Update: {} // The data expected passed to an "update" statement. + } + } + } +} +``` + +There is a difference between `selects`, `inserts`, and `updates`, because often you will set default values in your database for specific columns. +With default values you do not need to send any data over the network, even if that column is a "required" field. Our type system is granular +enough to handle these situations. + +## Injecting type definitions + +You can enrich the supabase client with the types you generated with Supabase. + +```ts +import { createClient } from '@supabase/supabase-js' +import { Database } from 'lib/database.types' + +const supabase = createClient( + process.env.SUPABASE_URL, + process.env.SUPABASE_ANON_KEY +) +``` + +## Type hints + +`supabase-js` always returns a `data` object (for success), and an `error` response (for unsuccessful requests). +This provides a simple interface to get the relevant types returned from any function: + +```ts +export async function getMovies() { + return await supabase.from('movies').select(`id, title`) +} + +type MoviesResponse = Awaited> +export type MoviesResponseSuccess = MoviesResponse['data'] +export type MoviesResponseError = MoviesResponse['error'] +``` + +## Nested tables + +For advanced queries such as nested tables, you may want to construct your own types. + +```ts +import supabase from '~/lib/supabase' +import type { Database } from '~/lib/database.types' + +async function getMovies() { + return await supabase.from('movies').select('id, title, actors(*)') +} + +type actors = Database['public']['Tables']['actors']['Row'] +type MoviesResponse = Awaited> +type MoviesResponseSuccess = MoviesResponse['data'] & { + actors: actors[] +} +``` diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/generated/.gitkeep b/apps/reference/_supabase_js_versioned_docs/version-v1/generated/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/generating-types.mdx b/apps/reference/_supabase_js_versioned_docs/version-v1/generating-types.mdx new file mode 100644 index 00000000000..a5089800e99 --- /dev/null +++ b/apps/reference/_supabase_js_versioned_docs/version-v1/generating-types.mdx @@ -0,0 +1,42 @@ +--- +id: generating-types +title: "Generating Types" +slug: generating-types +custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1_legacy.yml +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Supabase will soon release native type generators that dump your database types for various languages. For now, we support TypeScript [through third-party tools](/docs/guides/api/generating-types). + +## Usage with TypeScript + +`supabase-js` ships with type definitions for usage with TypeScript and for convenient IntelliSense auto-complete and documentation in your editor. + +When using TypeScript, you can pass the type of database row as a type parameter to the `from` method to get better auto-completion support down the chain. +If you don't provide a type for the row you need to explicitly pass `from('tableName')`. + +```ts +type Message = { + id: number; + inserted_at: string; + message: string; + user_id: string; + channel_id: number; + author: { username: string }; +} + +const response = await supabase + .from('messages') // Message maps to the type of the row in your database. + .select('*, author:user_id(username)') + .match({ channel_id: 2 }) // Your IDE will be able to help with auto-completion. +response.data // Response data will be of type Array. + +// If you don't provide a type for the row you need to explicitly pass `from('tableName')`. +const response = await supabase + .from('messages') + .select('*, author:user_id(username)') + .match({ channel_id: 2 }) +response.data // Response data will be of type Array. +``` \ No newline at end of file diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/index.mdx b/apps/reference/_supabase_js_versioned_docs/version-v1/index.mdx new file mode 100644 index 00000000000..d4f3a229100 --- /dev/null +++ b/apps/reference/_supabase_js_versioned_docs/version-v1/index.mdx @@ -0,0 +1,12 @@ +--- +id: index +title: "Supabase Client" +slug: supabase-client +custom_edit_url: ../../spec/supabase_js_v1_legacy.yml +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + +Supabase JavaScript. \ No newline at end of file diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/initializing.mdx b/apps/reference/_supabase_js_versioned_docs/version-v1/initializing.mdx new file mode 100644 index 00000000000..5b95cefa7dc --- /dev/null +++ b/apps/reference/_supabase_js_versioned_docs/version-v1/initializing.mdx @@ -0,0 +1,163 @@ +--- +id: initializing +title: "Initializing" +slug: initializing +custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1_legacy.yml +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +You can initialize a new Supabase client using the `createClient()` method. + +The Supabase client is your entrypoint to the rest of the Supabase functionality +and is the easiest way to interact with everything we offer within the Supabase ecosystem. + + + + +## Parameters + + +
    + +
  • +

    + + supabaseUrl + + + required + + + string + +

    +
    + +The unique Supabase URL which is supplied when you create a new project in your project dashboard. + +
    + +
  • + + +
  • +

    + + supabaseKey + + + required + + + string + +

    +
    + +The unique Supabase Key which is supplied when you create a new project in your project dashboard. + +
    + +
  • + + +
  • +

    + + options + + + optional + + + SupabaseClientOptions + +

    +
    + +No description provided. + +
    + +
  • + +
+ + + + + + + + + + + + + + +## Examples + +### createClient() + + + +```js +import { createClient } from '@supabase/supabase-js' + +// Create a single supabase client for interacting with your database +const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key') +``` + +### With additional parameters + + + +```js +import { createClient } from '@supabase/supabase-js' + +const options = { + schema: 'public', + headers: { 'x-my-custom-header': 'my-app-name' }, + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: true +} +const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key", options) +``` + +### API schemas + + + +```js +import { createClient } from '@supabase/supabase-js' + +// Provide a custom schema. Defaults to "public". +const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { + schema: 'other_schema' +}) +``` + +By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard. +Go to `Settings > API > Schema` and add the schema which you want to expose to the API. + +Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema. + +### Custom `fetch` implementation + + + +```js +import { createClient } from '@supabase/supabase-js' + +const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { + fetch: fetch.bind(globalThis) +}) +``` + +`supabase-js` uses the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) library to make HTTP requests, +but an alternative `fetch` implementation can be provided as an option. +This is most useful in environments where `cross-fetch` is not compatible (for instance Cloudflare Workers). \ No newline at end of file diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/installing.mdx b/apps/reference/_supabase_js_versioned_docs/version-v1/installing.mdx new file mode 100644 index 00000000000..37dca1ccac5 --- /dev/null +++ b/apps/reference/_supabase_js_versioned_docs/version-v1/installing.mdx @@ -0,0 +1,34 @@ +--- +id: installing +title: "Installing" +slug: installing +custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1_legacy.yml +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +All JavaScript libraries are built directly by the Supabase team. + +Other languages are built by the community and supported by Supabase. + +## JavaScript + +Via NPM +```bash +npm install @supabase/supabase-js +``` + +Via Yarn +```bash +yarn add @supabase/supabase-js +``` + +Find the source code on [GitHub](https://github.com/supabase/supabase-js). + +Or via CDN +```js + +//or + +``` \ No newline at end of file diff --git a/apps/reference/_supabase_js_versioned_docs/version-v1/intro.md b/apps/reference/_supabase_js_versioned_docs/version-v1/intro.md new file mode 100644 index 00000000000..c076ac88b67 --- /dev/null +++ b/apps/reference/_supabase_js_versioned_docs/version-v1/intro.md @@ -0,0 +1,16 @@ +--- +id: intro +title: 'Supabase JavaScript Library' +slug: / +sidebar_label: Supabase JavaScript Library +--- + +This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`. + +You can use the `supabase-js` library to: + +- interact with your Postgres database +- listen to database changes +- invoke Deno Edge Functions +- build login and user management functionality +- manage large files diff --git a/apps/reference/_supabase_js_versioned_sidebars/.gitkeep b/apps/reference/_supabase_js_versioned_sidebars/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/reference/_supabase_js_versioned_sidebars/version-v1-sidebars.json b/apps/reference/_supabase_js_versioned_sidebars/version-v1-sidebars.json new file mode 100644 index 00000000000..8687644761e --- /dev/null +++ b/apps/reference/_supabase_js_versioned_sidebars/version-v1-sidebars.json @@ -0,0 +1,138 @@ +{ + "sidebar": [ + { + "type": "category", + "label": "Getting Started", + "items": ["intro", "installing", "initializing", "generating-types"], + "collapsed": false + }, + { + "type": "category", + "label": "Auth", + "items": [ + "generated/auth-signup", + "generated/auth-signin", + "generated/auth-signout", + "generated/auth-session", + "generated/auth-user", + "generated/auth-update", + "generated/auth-setauth", + "generated/auth-onauthstatechange", + "generated/auth-api-getuser", + "generated/auth-api-resetpasswordforemail" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Auth (Server Only)", + "items": [ + "generated/auth-api-listusers", + "generated/auth-api-createuser", + "generated/auth-api-deleteuser", + "generated/auth-api-generatelink", + "generated/auth-api-inviteuserbyemail", + "generated/auth-api-sendmobileotp", + "generated/auth-api-updateuserbyid" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Functions", + "items": ["generated/invoke"], + "collapsed": true + }, + { + "type": "category", + "label": "Database", + "items": [ + "generated/select", + "generated/insert", + "generated/update", + "generated/upsert", + "generated/delete", + "generated/rpc" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Realtime", + "items": [ + "generated/subscribe", + "generated/removesubscription", + "generated/removeallsubscriptions", + "generated/getsubscriptions" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Storage", + "items": [ + "generated/storage-createbucket", + "generated/storage-getbucket", + "generated/storage-listbuckets", + "generated/storage-updatebucket", + "generated/storage-deletebucket", + "generated/storage-emptybucket", + "generated/storage-from-upload", + "generated/storage-from-download", + "generated/storage-from-list", + "generated/storage-from-update", + "generated/storage-from-move", + "generated/storage-from-copy", + "generated/storage-from-remove", + "generated/storage-from-createsignedurl", + "generated/storage-from-createsignedurls", + "generated/storage-from-getpublicurl" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Modifiers", + "items": [ + "generated/using-modifiers", + "generated/limit", + "generated/order", + "generated/range", + "generated/single", + "generated/maybesingle" + ], + "collapsed": true + }, + { + "type": "category", + "label": "Filters", + "items": [ + "generated/using-filters", + "generated/or", + "generated/not", + "generated/match", + "generated/eq", + "generated/neq", + "generated/gt", + "generated/gte", + "generated/lt", + "generated/lte", + "generated/like", + "generated/ilike", + "generated/is", + "generated/in", + "generated/contains", + "generated/containedby", + "generated/rangelt", + "generated/rangegt", + "generated/rangegte", + "generated/rangelte", + "generated/rangeadjacent", + "generated/overlaps", + "generated/textsearch", + "generated/filter" + ], + "collapsed": true + } + ] +} diff --git a/apps/reference/_supabase_js_versions.json b/apps/reference/_supabase_js_versions.json new file mode 100644 index 00000000000..868a38e32ae --- /dev/null +++ b/apps/reference/_supabase_js_versions.json @@ -0,0 +1 @@ +["v1"] diff --git a/apps/reference/babel.config.js b/apps/reference/babel.config.js new file mode 100644 index 00000000000..67526481891 --- /dev/null +++ b/apps/reference/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +} diff --git a/apps/reference/docs/about.mdx b/apps/reference/docs/about.mdx new file mode 100755 index 00000000000..07e696f4a9e --- /dev/null +++ b/apps/reference/docs/about.mdx @@ -0,0 +1,184 @@ +--- +id: about +title: Introduction +description: 'What is Supabase?' +slug: / +hide_table_of_contents: true +pagination_next: null +--- + +import ThemedImage from '@theme/ThemedImage' +import AngularLogo from '@site/static/img/libraries/angular-icon.svg' +import ExpoLogo from '@site/static/img/libraries/expo-icon.svg' +import DartLogo from '@site/static/img/libraries/dart-icon.svg' +import JavascriptLogo from '@site/static/img/libraries/javascript-icon.svg' +import NextjsDarkLogo from '@site/static/img/libraries/nextjs-dark-icon.svg' +import NextjsLightLogo from '@site/static/img/libraries/nextjs-light-icon.svg' +import ReactLogo from '@site/static/img/libraries/react-icon.svg' +import SolidJSLogo from '@site/static/img/libraries/solidjs-icon.svg' +import RedwoodJsLogo from '@site/static/img/libraries/redwoodjs-icon.svg' +import SvelteLogo from '@site/static/img/libraries/svelte-icon.svg' +import VuejsLogo from '@site/static/img/libraries/vuejs-icon.svg' +import useBaseUrl from '@docusaurus/useBaseUrl' +import Link from '@docusaurus/Link' +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' +import ButtonCard from '@site/src/components/ButtonCard' +const frameworks = [ + { + name: 'Angular', + logo: AngularLogo, + href: '/guides/with-angular', + }, + { + name: 'Expo', + logo: ExpoLogo, + href: 'https://github.com/supabase/examples/tree/main/supabase-js-v1/todo-list/expo-todo-list', + }, + { name: 'Flutter', logo: DartLogo, href: '/guides/with-flutter' }, + { + name: 'JavaScript', + logo: JavascriptLogo, + href: 'https://github.com/supabase/examples/tree/main/supabase-js-v1/auth/javascript-auth', + }, + { + name: 'Next.js', + themed: true, + logo: { + dark: '/img/libraries/nextjs-dark-icon.svg', + light: '/img/libraries/nextjs-light-icon.svg', + }, + href: '/guides/with-nextjs', + }, + { name: 'React', logo: ReactLogo, href: '/guides/with-react' }, + { + name: 'RedwoodJS', + logo: RedwoodJsLogo, + href: '/guides/with-redwoodjs', + }, + { name: 'SolidJS', logo: SolidJSLogo, href: '/guides/with-solidjs' }, + { name: 'Svelte', logo: SvelteLogo, href: '/guides/with-svelte' }, + { name: 'Vue', logo: VuejsLogo, href: '/guides/with-vue-3' }, +] + +Supabase is an open source Firebase alternative providing all the backend features you need to build a product. +You can use it completely, or just the features you need. + +[Start a project](https://app.supabase.com) with the hosted platform or learn how to [host Supabase](/docs/guides/hosting/overview) yourself. + +## Learn about features + +
+
+ {/* Auth */} +
+ +
+ {/* Auto-generated APIs */} +
+ +
+ {/* Database */} +
+ +
+ {/* Edge Functions */} +
+ +
+ {/* Realtime */} +
+ +
+ {/* File Storage */} +
+ +
+ {/* Observability */} +
+ +
+
+
+ +## Start with a framework + +Supabase is just Postgres, which makes it compatible with a large number of tools and frameworks. + +
+
+ {frameworks.map((x) => ( +
+ + ) : ( + + ) + } + class="card" + to={useBaseUrl(x.href)} + title={x.name} + description={x.description} + style={{ height: '100%' }} + /> +
+ ))} +
+
diff --git a/apps/reference/docs/architecture.mdx b/apps/reference/docs/architecture.mdx new file mode 100755 index 00000000000..cbf6530b138 --- /dev/null +++ b/apps/reference/docs/architecture.mdx @@ -0,0 +1,39 @@ +--- +id: architecture +title: Architecture +description: 'Supabase design and architecture' +# hide_table_of_contents: true +--- + +Supabase is open source. Wherever possible, we use and support existing tools rather than developing from scratch. +We choose open source tools which are scalable and we make them simple to use. + +![Supabase Architecture](/img/supabase-architecture.png) + +Supabase is not a 1-to-1 mapping of Firebase. While we are building many of the features that Firebase offers, we are not going about it the same way. + +Our technological choices are quite different from Firebase. Everything we use is open source. Wherever possible, we use and support existing tools rather than developing from scratch. + +Most notably, we use Postgres rather than a NoSQL store. This choice was deliberate. We believe that no other database offers the scalability and functionality required to compete with Firebase. + +## Feature Status + +| Product | Feature | Stage | Docs | +| -------------------------- | ---------------------- | ----- | ------------------------------------------------ | +| Database | Postgres | GA | [Link](/docs/guides/database) | +| Database | Webhooks | Alpha | | +| Database | Point in time Recovery | Alpha | | +| Realtime | Postgres Changes | Beta | [Link](/docs/guides/realtime/postgres-changes) | +| Realtime | Broadcast | Alpha | [Link](/docs/guides/realtime/broadcast) | +| Realtime | Presence | Alpha | [Link](/docs/guides/realtime/presence) | +| Storage | | Beta | [Link](/docs/guides/storage) | +| Storage | CDN | Beta | [Link](/docs/guides/storage-cdn) | +| Edge Functions | | Beta | [Link](/docs/guides/functions) | +| Auth | OAuth Providers | Beta | [Link](/docs/guides/auth/auth-apple) | +| Auth | Passwordless | Beta | [Link](/guides/auth/auth-magic-link) | +| Auth | Next.js Auth Helpers | Alpha | [Link](/docs/guides/auth/auth-helpers/nextjs) | +| Auth | SvelteKit Auth Helpers | Alpha | [Link](/docs/guides/auth/auth-helpers/sveltekit) | +| Public API | | Beta | [Link](/docs/reference/api) | +| CLI | | Beta | [Link](/docs/guides/cli) | +| Client Library: JavaScript | | GA | [Link](/docs/reference/javascript/next/) | +| Client Library: Dart | | Beta | [Link](/docs/reference/dart) | diff --git a/web/docs/company/aup.md b/apps/reference/docs/company/aup.md similarity index 100% rename from web/docs/company/aup.md rename to apps/reference/docs/company/aup.md diff --git a/web/docs/company/privacy.md b/apps/reference/docs/company/privacy.md similarity index 100% rename from web/docs/company/privacy.md rename to apps/reference/docs/company/privacy.md diff --git a/web/docs/company/sla.md b/apps/reference/docs/company/sla.md similarity index 74% rename from web/docs/company/sla.md rename to apps/reference/docs/company/sla.md index 366be52b0f9..00cbf36e740 100644 --- a/web/docs/company/sla.md +++ b/apps/reference/docs/company/sla.md @@ -3,21 +3,21 @@ id: sla title: Service Level Agreement --- -The following Service Level Agreement, which is incorporated into and forms part of the Subscription Agreement between Supabase, Inc. ("Supabase") and Customer (the "Agreement"), will apply to the Services for Enterprise Customers specified in an Order Form during the applicable Subscription Term: +The following Service Level Agreement, which is incorporated into and forms part of the Subscription Agreement between Supabase, Inc. ("Supabase") and Customer (the "Agreement"), will apply to the Services for Enterprise Customers specified in an Order Form during the applicable Subscription Term: ## Platform + ### 1. Uptime Commitment Supabase will provide Actual Availability for at least ninety-nine and nine tenths percent (99.9%) of the total time in each calendar month during the Subscription Term, as measured by Supabase (the **"Uptime Commitment"**). - ### 2. Service Credits -If the Uptime Commitment is not met during any particular calendar month during the Subscription Term, then Customer will be eligible for a service credit ("Service Credit"), provided that Customer reports to Supabase such failure to meet the Uptime Commitment and requests such Service Credit in accordance with this Exhibit. The amount of any Service Credit due hereunder shall be calculated as follows: -X * Y, where X = the total fees due from Customer to Supabase for the affected Services for the relevant calendar month (regardless of when billed or payable), and Y = the Credit Percentage corresponding with the Actual Availability provided (as a percentage of total time) for the relevant calendar month, as set forth in the table below. +If the Uptime Commitment is not met during any particular calendar month during the Subscription Term, then Customer will be eligible for a service credit ("Service Credit"), provided that Customer reports to Supabase such failure to meet the Uptime Commitment and requests such Service Credit in accordance with this Exhibit. The amount of any Service Credit due hereunder shall be calculated as follows: +X \* Y, where X = the total fees due from Customer to Supabase for the affected Services for the relevant calendar month (regardless of when billed or payable), and Y = the Credit Percentage corresponding with the Actual Availability provided (as a percentage of total time) for the relevant calendar month, as set forth in the table below. | Actual Availability | Credit Percentage | -|----------------------------------------------------|-------------------| +| -------------------------------------------------- | ----------------- | | Less than 99.9% but greater than or equal to 99.0% | 10% | | Less than 99.0% but greater than or equal to 98.0% | 15% | | Less than 98.0% but greater than or equal to 96.0% | 20% | @@ -33,7 +33,7 @@ All capitalized words used but not defined in this Service Level Agreement have #### 4.1 Scheduled Availability -"Scheduled Availability" means the time, in minutes, that the applicable Services are generally accessible and available to Customer’s Permitted Users. +"Scheduled Availability" means the time, in minutes, that the applicable Services are generally accessible and available to Customer’s Permitted Users. #### 4.2 Unscheduled Downtime @@ -41,7 +41,7 @@ All capitalized words used but not defined in this Service Level Agreement have #### 4.3 Actual Availability -"Actual Availability" means Scheduled Availability less Unscheduled Downtime. +"Actual Availability" means Scheduled Availability less Unscheduled Downtime. ## Support @@ -51,39 +51,38 @@ Supabase Support Service Level Agreements. **Critical Issue** -Defect resulting in full or partial system outage or a condition that makes Supabase unusable -or unavailable in production for all of Customer’s Users. +Defect resulting in full or partial system outage or a condition that makes Supabase unusable +or unavailable in production for all of Customer’s Users. ### 2. High **Significant Business Disruption** -Issue resulting in a situation meaning major functionality is impacted and -significant performance degradation is experienced. Issue impacts significant proportion of user base and / or major -Supabase functionality. +Issue resulting in a situation meaning major functionality is impacted and +significant performance degradation is experienced. Issue impacts significant proportion of user base and / or major +Supabase functionality. ### 3. Normal **Minor Feature or Functional Issue / General Question** -Issue results in a component of Supabase not -performing as expected or documented. An inquiry by a Customer representative regarding a general technical issue -or general question. +Issue results in a component of Supabase not +performing as expected or documented. An inquiry by a Customer representative regarding a general technical issue +or general question. ### 4. Low **Minor Issue / Feature Request** -An Information request about Supabase or feature request. +An Information request about Supabase or feature request. ## Target response times -| Severity Level | Standard | Priority | Priority Plus | -|----------------|--------------------------------------------|----------------------------------|-----------------------------------| -| 1. Urgent | 1 business hour
24/7 × 365 | 1 business hour
24/7 × 365 | 1 business hour
24/7 × 365 | +| Severity Level | Standard | Priority | Priority Plus | +| -------------- | ------------------------------------- | ------------------------------------- | -------------------------------------- | +| 1. Urgent | 1 business hour
24/7 × 365 | 1 business hour
24/7 × 365 | 1 business hour
24/7 × 365 | | 2. High | 4 business hours
Monday - Friday | 2 business hours
Monday - Friday | 2 business hours
24/7 × 365 | | 3. Normal | 1 business day
Monday - Friday | 1 business day
Monday - Friday | 12 business hours
Monday - Friday | | 4. Low | 2 business days
Monday - Friday | 2 business days
Monday - Friday | 1 business day
Monday - Friday | - Business hours are from 6am to 6pm (local time), except where otherwise stated. diff --git a/web/docs/company/terms.md b/apps/reference/docs/company/terms.md similarity index 100% rename from web/docs/company/terms.md rename to apps/reference/docs/company/terms.md diff --git a/web/docs/faq.md b/apps/reference/docs/faq.md similarity index 90% rename from web/docs/faq.md rename to apps/reference/docs/faq.md index eaba200f18c..044a73f9ec0 100755 --- a/web/docs/faq.md +++ b/apps/reference/docs/faq.md @@ -14,17 +14,17 @@ Self-hosting Supabase is free. If you wish to use our cloud-platform, we provide ### How do I host Supabase? -You can use the docker-compose script [here](https://github.com/supabase/supabase/tree/master/docker), and find detailed instructions [here](/docs/guides/hosting/overview). +You can use the docker-compose script [here](https://github.com/supabase/supabase/tree/master/docker), and find detailed instructions [here](/docs/guides/hosting/overview). -Supabase is an amalgamation of open source tools. Some of these tools are made by Supabase (like our [Realtime Server](https://github.com/supabase/realtime)), some we support directly (like [PostgREST](http://postgrest.org/en/v7.0.0/)), and some are third-party tools (like [KonSupabase is an amalgamation open sourceg](https://github.com/Kong/kong)). +Supabase is an amalgamation of open source tools. Some of these tools are made by Supabase (like our [Realtime Server](https://github.com/supabase/realtime)), some we support directly (like [PostgREST](http://postgrest.org/en/v7.0.0/)), and some are third-party tools (like [KonSupabase is an amalgamation open sourceg](https://github.com/Kong/kong)). All of the tools we use in Supabase are MIT, Apache 2.0, or PostgreSQL licensed. This is one of the requirements to be considered for the Supabase stack. ### How can you be a Firebase alternative if you're built with a relational database? -We started Supabase because we love the functionality of Firebase, but we personally experienced the scaling issues that many others experienced. We chose Postgres because it's well-trusted, with phenomenal scalability. +We started Supabase because we love the functionality of Firebase, but we personally experienced the scaling issues that many others experienced. We chose Postgres because it's well-trusted, with phenomenal scalability. -Our goal is to make Postgres as easy to use as Firebase, so that you no longer have to choose between usability and scalability. +Our goal is to make Postgres as easy to use as Firebase, so that you no longer have to choose between usability and scalability. We're sure that once you start using Postgres, you'll love it more than any other database. ### Do you support `[some other database]`? @@ -33,7 +33,6 @@ We only support PostgreSQL. It's unlikely we'll ever move away from Postgres; ho ### Do you have a library for `[some other language]`? -We officially support [JavaScript](/docs/reference/javascript/supabase-client) and [Dart](/docs/reference/dart/installing). +We officially support [JavaScript](/docs/reference/javascript/installing) and [Dart](/docs/reference/dart/installing). You can find community-supported libraries in our [GitHub Community](https://github.com/supabase-community), and you can also help us to identify the most popular languages by [voting for a new client library](https://github.com/supabase/supabase/discussions/5). - diff --git a/web/docs/going-into-prod.mdx b/apps/reference/docs/going-into-prod.mdx similarity index 84% rename from web/docs/going-into-prod.mdx rename to apps/reference/docs/going-into-prod.mdx index 1abefc05cdb..ffa0ca1f879 100644 --- a/web/docs/going-into-prod.mdx +++ b/apps/reference/docs/going-into-prod.mdx @@ -47,17 +47,6 @@ After developing your project and deciding it's time to Go Live With Real Users, - Nightly backups for Pro tier projects are available on the Supabase dashboard for up to 7 days. - Upgrading to the Supabase Pro Tier will give you access to email support on support@supabase.io -## Platform status - -If Supabase experiences outages, we keep you as informed as possible, as early as possible. We provide the following feedback channels: - -- Status page: [status.supabase.com](https://status.supabase.com/) -- RSS Feed: [status.supabase.com/history.rss](https://status.supabase.com/history.rss) -- Atom Feed: [status.supabase.com/history.atom](https://status.supabase.com/history.atom) -- Slack Alerts: You can receive updates via the RSS feed, using Slack's [built-in RSS functionality](https://slack.com/help/articles/218688467-Add-RSS-feeds-to-Slack)
`/feed subscribe https://status.supabase.com/history.atom` - -Make sure to review our [SLA](/docs/company/sla) for details on our commitment to Platform Stability. - ## Next steps This checklist is always growing so be sure to check back frequently, and also feel free to suggest additions and amendments by making a PR on [GitHub](https://github.com/supabase/supabase). diff --git a/apps/reference/docs/gotrue/client/.gitkeep b/apps/reference/docs/gotrue/client/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/web/docs/gotrue/server/about.md b/apps/reference/docs/gotrue/server/about.md similarity index 94% rename from web/docs/gotrue/server/about.md rename to apps/reference/docs/gotrue/server/about.md index 4acef396959..e2072b9a027 100644 --- a/web/docs/gotrue/server/about.md +++ b/apps/reference/docs/gotrue/server/about.md @@ -205,6 +205,10 @@ Controls the minimum amount of time that must pass before sending another signup If you do not require email confirmation, you may set this to `true`. Defaults to `false`. +`MAILER_SECURE_EMAIL_CHANGE_ENABLED` - `bool` + +If `true`, send an email to both the user's current and new email with a confirmation link, otherwise send an email with confirmation link only to new email. Defaults to `true`. + `MAILER_URLPATHS_INVITE` - `string` URL path to use in the user invite email. Defaults to `/`. @@ -252,7 +256,8 @@ Default Content (if template is unavailable):

You have been invited

- You have been invited to create a user on {{ .SiteURL }}. Follow this link to accept the invite: + You have been invited to create a user on {{ .SiteURL }}. Follow this link to + accept the invite:

Accept the invite

``` @@ -309,7 +314,10 @@ Default Content (if template is unavailable): ```html

Confirm Change of Email

-

Follow this link to confirm the update of your email from {{ .Email }} to {{ .NewEmail }}:

+

+ Follow this link to confirm the update of your email from {{ .Email }} to {{ + .NewEmail }}: +

Change Email

``` @@ -631,7 +639,6 @@ Returns: } ``` - ### **PUT /admin/users/{user_id}** Updates a user. Requires your `service_role` API key and thus should only be @@ -666,6 +673,23 @@ Returns: } ``` +### **POST /admin/generate_link** + +Returns the corresponding email action link based on the type specified. The response also contains the query params of the action link as separate JSON fields for convenience (along with the email OTP from which the corresponding token is generated). + +Returns: + +```js +{ + "action_link": "http://localhost:9999/verify?token=TOKEN&type=TYPE&redirect_to=REDIRECT_URL", + "email_otp": "EMAIL_OTP", + "hashed_token": "TOKEN", + "verification_type": "TYPE", + "redirect_to": "REDIRECT_URL", + ... +} +``` + ### **DELETE /admin/users/{user_id}** Deletes a user. Requires your `service_role` API key and thus should only be diff --git a/web/docs/guides/api.mdx b/apps/reference/docs/guides/api.mdx similarity index 59% rename from web/docs/guides/api.mdx rename to apps/reference/docs/guides/api.mdx index edebca59f58..a563dc36065 100644 --- a/web/docs/guides/api.mdx +++ b/apps/reference/docs/guides/api.mdx @@ -2,100 +2,103 @@ id: api title: APIs description: Auto-generating and Realtime APIs. +sidebar_label: Overview --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' +import useBaseUrl from '@docusaurus/useBaseUrl' ## Overview -Supabase generates three types of API directly from your database schema. +Supabase generates three types of API directly from your database schema. - REST - interact with your database through a restful interface. - Realtime - listen to database changes. -- GraphQL - [in beta](https://supabase.com/blog/2021/12/03/pg-graphql). +- GraphQL - [in beta](https://supabase.com/blog/pg-graphql). The APIs are: -- **Instant and auto-generated.**
As you update your database the changes are immediately accessible through your API. -- **Self documenting.**
Supabase generates documentation in the Dashboard which updates as you make database changes. -- **Secure.**
The API is configured to work with PostgreSQL's Row Level Security, provisioned behind an API gateway with key-auth enabled. +- **Instant and auto-generated.**
As you update your database the changes are immediately accessible through your API. +- **Self documenting.**
Supabase generates documentation in the Dashboard which updates as you make database changes. +- **Secure.**
The API is configured to work with PostgreSQL's Row Level Security, provisioned behind an API gateway with key-auth enabled. - **Fast.**
Our benchmarks for basic reads are more than 300% faster than Firebase. The API is a very thin layer on top of Postgres, which does most of the heavy lifting. - **Scalable.**
The API can serve thousands of simultaneous requests, and works well for Serverless workloads. +### REST API {#rest-api-overview} -### REST API - -Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres. +Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres. It provides everything you need from a CRUD API: - Basic CRUD operations -- Deeply nested joins, allowing you to fetch data from multiple tables in a single fetch +- Deeply nested joins, allowing you to fetch data from multiple tables in a single fetch - Works with Postgres Views -- Works with Postgres Functions +- Works with Postgres Functions - Works with the Postgres security model - including Row Level Security, Roles, and Grants. - +
+ +
-### GraphQL API +### GraphQL API {#graphql-api-overview} :::note -GraphQL is in Beta, and may have breaking changes. It is only available on self-hosted setups and Supabase projects created after 28th March 2022. +GraphQL is in Beta, and may have breaking changes. It is only available on self-hosted setups and Supabase projects created after 28th March 2022. ::: -GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/2021/12/03/pg-graphql), an open source PostgreSQL extension for GraphQL. +GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/pg-graphql), an open source PostgreSQL extension for GraphQL. -### Realtime API +### Realtime API {#realtime-api-overview} -Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets. +Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets. Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications. ## Getting started -All APIs are auto-created from Database tables. After you have added tables or functions to your database, you can use the APIs provided. +All APIs are auto-created from Database tables. After you have added tables or functions to your database, you can use the APIs provided. ### Creating API Routes -API routes are automatically created when you create Postgres Tables, Views, or Functions. +API routes are automatically created when you create Postgres Tables, Views, or Functions. -Let's create our first -API route by creating a table called `todos` (which will store some public user information). -This will create a corresponding route `todos` which can accept `GET`, `POST`, `PATCH`, & `DELETE` requests. +Let's create our first +API route by creating a table called `todos` to store tasks. +This creates a corresponding route `todos` which can accept `GET`, `POST`, `PATCH`, & `DELETE` requests. - + groupId="dashboard-or-sql" + defaultValue="dashboard" + values={[ + {label: 'Dashboard', value: 'dashboard'}, + {label: 'SQL', value: 'sql'}, + ]}> -```sh -1. Go to the "Table editor" section. -2. Click "New Table". -3. Enter the table name "todos". -4. Click "Save". -5. Click "New Column". -6. Enter the column name "task" and make the type "text". -7. Click "Save". -``` + + +1. Go to the [Table editor](https://app.supabase.com/project/_/editor) page in the Dashboard. +1. Click **New Table** and create a table with the name `todos`. +1. Click **Save**. +1. Click **New Column** and create a column with the name `task` and type `text`. +1. Click **Save**. - + ```sql -- Create a table called "todos" with a column to store tasks. @@ -113,19 +116,20 @@ create table todos ( Every Supabase project has a unique API URL. Your API is secured behind an API gateway which requires an API Key for every request. - -```sh -1. Go to the "Settings" section. -2. Click "API" in the sidebar. -3. Find your API URL in this page. -4. Find your "anon" and "service_role" keys on this page. -``` +1. Go to the [Settings](https://app.supabase.com/project/_/settings/general) page in the Dashboard. +2. Click **API** in the sidebar. +3. Find your API `URL`, `anon`, and `service_role` keys on this page. -The REST API and the GraphQL API are both accessible through this URL: +The REST API and the GraphQL API are both accessible through this URL: - REST: `https://.supabase.co/rest/v1` - GraphQL: `https://.supabase.co/graphql/v1` @@ -134,43 +138,32 @@ Both of these routes require the `anon` key to be passed through an `apikey` hea #### API Keys - -You can find the Keys inside the Dashboard in the same location as the URL above. - You are provided with two keys: - an `anon` key, which is safe to be used in a browser context. - a `service_role` key, which should only be used on a server. This key can bypass Row Level Security. NEVER use this key in a browser. +### Accessing the docs in the Dashboard -### Accessing the Docs +#### REST API {#rest-api-dashboard-docs} -#### REST API - -Supabase generates documentation in the Dashboard which updates as you make database changes. +Supabase generates documentation in the [Dashboard](https://app.supabase.com) which updates as you make database changes. Let's view the documentation for a `countries` table which we created in our database. - - - -```sh -1. Go to the "API" section. -2. Find "todos" in the "Tables and Views" section. +1. Go to the [API](https://app.supabase.com/project/_/api) page in the Dashboard. +2. Find the `countries` table under **Tables and Views** in the sidebar. 3. Switch between the JavaScript and the cURL docs using the tabs. -``` - - - -#### GraphQL +#### GraphQL The GraphQL Endpoint that we provide (`https://.supabase.co/graphql/v1`) is compatible with any GraphiQL implementation that can pass an `apikey` header. Some suggested applications: @@ -182,22 +175,22 @@ Some suggested applications: ## Using the API - -### REST API +### REST API You can interact with your API directly via HTTP requests, or you can use the client libraries which we provide. -Let's see how to make a request to the `todos` table which we created in the first step, +Let's see how to make a request to the `todos` table which we created in the first step, using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_ANON_KEY`) we provided: - - + groupId="language" + defaultValue="javascript" + values={[ + {label: 'JavaScript', value: 'javascript'}, + {label: 'cURL', value: 'curl'}, + ]}> + + ```javascript // Initialize the JS client @@ -205,13 +198,11 @@ import { createClient } from '@supabase/supabase-js' const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY) // Make a request -const { data: todos, error } = await supabase - .from('todos') - .select('*') +const { data: todos, error } = await supabase.from('todos').select('*') ``` - + ```bash # Append /rest/v1/ to your URL, and then use the table name as the route @@ -223,32 +214,33 @@ curl '/rest/v1/todos' \ -JS Reference: [select()](/docs/reference/javascript/select), -[insert()](/docs/reference/javascript/insert), -[update()](/docs/reference/javascript/update), -[upsert()](/docs/reference/javascript/upsert), -[delete()](/docs/reference/javascript/delete), -[rpc()](/docs/reference/javascript/rpc) (call Postgres functions). +JS Reference: [select()](../reference/javascript/select), +[insert()](../reference/javascript/insert), +[update()](../reference/javascript/update), +[upsert()](../reference/javascript/upsert), +[delete()](../reference/javascript/delete), +[rpc()](../reference/javascript/rpc) (call Postgres functions). +### GraphQL API -### GraphQL API - -:::note +:::note To rebuild your GraphQL schema from the SQL schema, call `select graphql.rebuild_schema();`. Be sure to rebuild the GraphQL schema after altering the SQL schema. ::: -You can use any GraphQL client with the Supabase GraphQL API. For our GraphQL example we will use [urql](https://formidable.com/open-source/urql/docs/). +You can use any GraphQL client with the Supabase GraphQL API. For our GraphQL example we will use [urql](https://formidable.com/open-source/urql/docs/). - + groupId="language" + defaultValue="javascript" + values={[ + {label: 'JavaScript', value: 'javascript'}, + {label: 'cURL', value: 'curl'}, + ]}> + + ```javascript import { createClient, useQuery } from 'urql' @@ -263,7 +255,7 @@ const headers = { // See: https://formidable.com/open-source/urql/docs/basics/react-preact/#setting-up-the-client const client = createClient({ url: '/graphql/v1', - fetchOptions: function createFetchOptions() { + fetchOptions: function createFetchOptions() { return { headers } }, }) @@ -292,7 +284,7 @@ const { data, fetching, error } = result ``` - + ```bash # Append /graphql/v1/ to your URL, and then use the table name as the route @@ -305,32 +297,36 @@ curl --request POST '/graphql/v1' \ - ### Realtime API By default Realtime is disabled on your database. Let's turn on Realtime for the `todos` table. - + groupId="dashboard-or-sql" + defaultValue="dashboard" + values={[ + {label: 'Dashboard', value: 'dashboard'}, + {label: 'SQL', value: 'sql'}, + ]}> -```sh -1. Go to the "Database" section. -2. Click on "Replication" in the sidebar. -3. Control which database events are sent by toggling the Insert/Update/Delete toggles. -4. Control which tables broadcast changes by clicking into the "Source" and toggling the tables. -``` + + +1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard. +2. Click on **Replication** in the sidebar. +3. Control which database events are sent by toggling **Insert**, **Update**, and **Delete**. +4. Control which tables broadcast changes by selecting **Source** and toggling each table. - + ```sql alter publication supabase_realtime add table todos; @@ -339,14 +335,7 @@ alter publication supabase_realtime add table todos; -Now we can listen to any new data that is inserted into the `todos` table: - - - +From the client, we can listen to any new data that is inserted into the `todos` table: ```javascript // Initialize the JS client @@ -358,46 +347,41 @@ const handleInserts = (payload) => { console.log('Change received!', payload) } -// Listen to unserts +// Listen to inserts const { data: todos, error } = await supabase .from('todos') - .on('INSERT', handleUpdates) + .on('INSERT', handleInserts) .subscribe() ``` - - - -Use [subscribe()](/docs/reference/javascript/subscribe) to listen to database changes. +Use [subscribe()](/docs/reference/javascript/subscribe) to listen to database changes. The Realtime API works through PostgreSQL's replication functionality. Postgres sends database changes to a [publication](/docs/guides/database/replication#publications) called `supabase_realtime`, and by managing this publication you can control which data is broadcast. ## API Security +### Securing your Routes -### Securing your Routes - - -Your API is designed to work with Postgres Row Level Security. If you use Supabase [Auth](/docs/guides/auth), you can restrict data based on the logged-in user. -To control access to your data, you can use [Policies](/docs/guides/auth#policies). -When you create a table in Postgres, Row Level Security is disabled by default. Make sure you secure it by [enabling RLS](/docs/guides/api#securing-your-routes). +Your API is designed to work with Postgres Row Level Security (RLS). If you use Supabase [Auth](/guides/auth), you can restrict data based on the logged-in user. +To control access to your data, you can use [Policies](/guides/auth#policies). +When you create a table in Postgres, Row Level Security is disabled by default. To enable RLS: - + groupId="dashboard-or-sql" + defaultValue="dashboard" + values={[ + {label: 'Dashboard', value: 'dashboard'}, + {label: 'SQL', value: 'sql'}, + ]}> -```sh -1. Go to the "Authentication" section. -2. Click on "Policies" in the sidebar. -3. Click "Enable RLS" to enable Row Level Security. -``` + + +1. Go to the [Authentication](https://app.supabase.com/project/_/auth/users) page in the Dashboard. +2. Click on **Policies** in the sidebar. +3. Select **Enable RLS** to enable Row Level Security. - + ```sql alter table todos enable row level security; @@ -406,24 +390,25 @@ alter table todos enable row level security; -### The `service_role` key +### The `service_role` key +Never expose the `service_role` key in a browser or anywhere where a user can see it. This Key is designed to bypass Row Level Security - so it should only be used on a private server. -Never expose the `service_role` key in a browser or anywhere where a user can see it. This Key can is designed to bypass Row Level Security - so it should only be used on a private server. - -We have [partnered with GitHub](https://supabase.com/blog/2022/03/28/community-day#supabase-is-now-a-github-secret-scanning-partner) to scan for Supabase `service_role` keys pushed to public repositories. +We have [partnered with GitHub](https://github.blog/changelog/2022-03-28-supabase-is-now-a-github-secret-scanning-partner/) to scan for Supabase `service_role` keys pushed to public repositories. If they detect any keys with service_role privileges being pushed to GitHub, they will forward the API key to us, so that we can automatically revoke the detected secrets and notify you, protecting your data against malicious actors. ### Safeguards towards accidental deletes and updates -For all projects, by default, the Postgres extension [safeupdate](https://github.com/eradman/pg-safeupdate) is enabled for all queries coming from the API. +For all projects, by default, the Postgres extension [safeupdate](https://github.com/eradman/pg-safeupdate) is enabled for all queries coming from the API. This ensures that any `delete()` or `update()` would fail if there are no accompanying filters provided. To confirm that safeupdate is enabled for queries going through the API of your project, the following query could be run: + ```sql select usename,useconfig from pg_shadow where usename = 'authenticator' ; ``` The expected value for `useconfig` should be: + ``` ["session_preload_libraries=supautils, safeupdate"] ``` diff --git a/web/docs/guides/api/generating-types.mdx b/apps/reference/docs/guides/api/generating-types.mdx similarity index 92% rename from web/docs/guides/api/generating-types.mdx rename to apps/reference/docs/guides/api/generating-types.mdx index db7882f66d0..21ce6c15340 100644 --- a/web/docs/guides/api/generating-types.mdx +++ b/apps/reference/docs/guides/api/generating-types.mdx @@ -1,6 +1,6 @@ --- id: generating-types -title: "Generating Types" +title: 'Generating Types' description: How to generate types for your API and Supabase libraries. --- @@ -31,9 +31,9 @@ Important notes: After you have generated your types, you can use them in your TypeScript projects: ```ts -import { NextApiRequest, NextApiResponse } from "next" -import { createClient } from "@supabase/supabase-js" -import { definitions } from "../../types/supabase" +import { NextApiRequest, NextApiResponse } from 'next' +import { createClient } from '@supabase/supabase-js' +import { definitions } from '../../types/supabase' const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, @@ -42,11 +42,11 @@ const supabase = createClient( export default async (req: NextApiRequest, res: NextApiResponse) => { const allOnlineUsers = await supabase - .from("users") - .select("*") - .eq("status", "ONLINE") + .from('users') + .select('*') + .eq('status', 'ONLINE') res.status(200).json(allOnlineUsers) -}; +} ``` For more advance type-support, check out [`postgrest-js-tools`](https://github.com/mzalevski/postgrest-js-tools). @@ -56,6 +56,7 @@ For more advance type-support, check out [`postgrest-js-tools`](https://github.c One way to keep your type definitions in sync with your database is to set up a GitHub action that runs on a schedule. The following script can be run in your terminal to produce the file `types/database/index.ts`. + ``` npx openapi-typescript https://your-project.supabase.co/rest/v1/?apikey=your-anon-key --output types/database/index.ts ``` @@ -67,7 +68,7 @@ You can add this script to your `package.json` and run it using `npm run update- ``` You can use GitHub actions to generate this file automatically. This script will commit the change to your repo every night. -Create a file `.github/workflows/update-types.yml` and add the following snippet into this file to define the action along with the environment variables. +Create a file `.github/workflows/update-types.yml` and add the following snippet into this file to define the action along with the environment variables. ```yml name: Update database types @@ -115,4 +116,4 @@ Alternatively, you can use a community-supported GitHub action: [generate-supaba ## Resources -- [Generating Supabase types with GitHub Actions](https://blog.esteetey.dev/how-to-create-and-test-a-github-action-that-generates-types-from-supabase-database) \ No newline at end of file +- [Generating Supabase types with GitHub Actions](https://blog.esteetey.dev/how-to-create-and-test-a-github-action-that-generates-types-from-supabase-database) diff --git a/web/docs/guides/auth.mdx b/apps/reference/docs/guides/auth.mdx similarity index 66% rename from web/docs/guides/auth.mdx rename to apps/reference/docs/guides/auth.mdx index 12dac17f276..1505754d7ef 100644 --- a/web/docs/guides/auth.mdx +++ b/apps/reference/docs/guides/auth.mdx @@ -2,22 +2,15 @@ id: auth title: Auth description: Use Supabase to Authenticate and Authorize your users. +sidebar_label: Overview --- import Link from '@docusaurus/Link' import Tabs from '@theme/Tabs' import TabItem from '@theme/TabItem' import providers from '@site/src/data/authProviders' - - +import ButtonCard from '@site/src/components/ButtonCard' +import useBaseUrl from '@docusaurus/useBaseUrl' ## Overview @@ -26,9 +19,20 @@ There are two parts to every Auth system: - **Authentication:** should this person be allowed in? If yes, who are they? - **Authorization:** once they are in, what are they allowed to do? -Supabase Auth is designed to work either as a standalone product, or deeply integrated with the other Supabase products. +Supabase Auth is designed to work either as a standalone product, or deeply integrated with the other Supabase products. Postgres is at the heart of everything we do, and the Auth system follows this principle. We leverage Postgres' built-in Auth functionality wherever possible. +Here's a quick, 2 minute tour of the Auth features built-in to Supabase: + +
+ +
+ ## Authentication You can authenticate your users in several ways: @@ -38,64 +42,86 @@ You can authenticate your users in several ways: - Social providers. - Phone logins. -### Providers +### Providers -We provide a suite of Providers and login methods. +We provide a suite of Providers and login methods, as well as [Auth helpers](/docs/guides/auth/auth-helpers/).
{providers.map((x) => (
- -
-
+ +
+
{x.logo && {x.name}}

{x.name}

- {x.official ? - Official - : - - Unofficial - - } + {x.official ? ( + Official + ) : ( + Unofficial + )}

-
+
Platform: {x.platform.toString()}
-
+
Self-Hosted: {x.selfHosted.toString()}
- +
))}
+### Configure third-party providers -### Simple interface - -You can enable third-providers with the click of a button by navigating to Authentication > Settings > External OAuth Providers and inputting your `Client ID` and `Secret` for each. +You can enable third-party providers with the click of a button by navigating to Authentication > Settings > Auth Providers and inputting your `Client ID` and `Secret` for each. ![OAuth Logins.](/img/supabase-oauth-logins.png) - ## Authorization - When you need granular authorization rules, nothing beats PostgreSQL's Row Level Security (RLS). Policies are PostgreSQL's rule engine. They are incredibly powerful and flexible, allowing you to write complex SQL rules which fit your unique business needs. Get started with our [Row Level Security Guides](/docs/guides/auth/row-level-security). - ### Row Level Security Authentication only gets you so far. When you need granular authorization rules, nothing beats PostgreSQL's [Row Level Security (RLS)](https://www.postgresql.org/docs/current/ddl-rowsecurity.html). Supabase makes it simple to turn RLS on and off. @@ -109,7 +135,12 @@ Authentication only gets you so far. When you need granular authorization rules, [Policies](https://www.postgresql.org/docs/current/sql-createpolicy.html) are PostgreSQL's rule engine. They are incredibly powerful and flexible, allowing you to write complex SQL rules which fit your unique business needs. With policies, your database becomes the rules engine. Instead of repetitively filtering your queries, like this ... @@ -134,7 +165,6 @@ let { data, error } = await supabase.from('users').select('user_id, name') // Still => { id: 'd0714948', name: 'Jane' } ``` - ### How It Works 1. A user signs up. Supabase creates a new user in the `auth.users` table. @@ -145,14 +175,17 @@ let { data, error } = await supabase.from('users').select('user_id, name') Supabase provides a special function in Postgres, `auth.uid()`, which extracts the user's UID from the JWT. This is especially useful when creating policies. - - ## User Management Supabase makes it simple to manage your users. When users sign up, Supabase assigns them a unique ID. You can reference this ID anywhere in your database. For example, you might create a `profiles` table referencing `id` in the `auth.users` table using a `user_id` field. @@ -160,7 +193,6 @@ When users sign up, Supabase assigns them a unique ID. You can reference this ID Supabase provides the routes to [sign up](/docs/reference/javascript/auth-signup), [log in](/docs/reference/javascript/auth-signin), [log out](/docs/reference/javascript/auth-signout), and manage users in your apps and websites. - ## Next Steps - Sign in: [app.supabase.com](https://app.supabase.com) diff --git a/web/docs/guides/auth/auth-apple.mdx b/apps/reference/docs/guides/auth/auth-apple.mdx similarity index 98% rename from web/docs/guides/auth/auth-apple.mdx rename to apps/reference/docs/guides/auth/auth-apple.mdx index fc3f776eca1..653ebcd527b 100644 --- a/web/docs/guides/auth/auth-apple.mdx +++ b/apps/reference/docs/guides/auth/auth-apple.mdx @@ -71,7 +71,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Configure your Services ID diff --git a/web/docs/guides/auth/auth-azure.mdx b/apps/reference/docs/guides/auth/auth-azure.mdx similarity index 83% rename from web/docs/guides/auth/auth-azure.mdx rename to apps/reference/docs/guides/auth/auth-azure.mdx index 04e956067e5..4123c627219 100644 --- a/web/docs/guides/auth/auth-azure.mdx +++ b/apps/reference/docs/guides/auth/auth-azure.mdx @@ -40,7 +40,7 @@ Azure OAuth consists of four broad steps: This will serve as the `client_id` when you make API calls to authenticate the user. -- Once your app has been registered, the client id can be found under the [list of app registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) under the column titled "Application (client) ID". +- Once your app has been registered, the client id can be found under the [list of app registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) under the column titled "Application (client) ID". ![Obtain the client id](/img/guides/auth-azure/azure-client-id.png) @@ -52,10 +52,19 @@ This will serve as the `client_secret` when you make API calls to authenticate t - Under "Essentials", click on "Client credentials". - Navigate to the "Client secrets" tab and select "New client secret". - Enter a description and choose your preferred expiry for the secret. -- Once the secret is generated, save the value (not the secret ID). +- Once the secret is generated, save the `value` (not the secret ID). ![Obtain the client secret](/img/guides/auth-azure/azure-client-secret.png) +## Obtain the Tenant URL + +This will allow your users to use your custom Azure login page when logging in. + +- Select the Directory (Tenant) ID value. +- The Azure Tenant URL should look like this: `https://login.microsoftonline.com/` + +![Obtain the tenant url](/img/guides/auth-azure/azure-tenant-url.png) + ### Add login code to your client app The JavaScript client code is documented in the [Supabase OAuth Reference](/docs/reference/javascript/auth-signin#sign-in-using-third-party-providers). @@ -70,11 +79,14 @@ Add a function which you can call from a button, link, or UI element. ```js async function signInWithAzure() { - const { user, session, error } = await supabase.auth.signIn({ - provider: 'azure', - }, { + const { user, session, error } = await supabase.auth.signIn( + { + provider: 'azure', + }, + { scopes: 'email', - }) + } + ) } ``` diff --git a/web/docs/guides/auth/auth-bitbucket.mdx b/apps/reference/docs/guides/auth/auth-bitbucket.mdx similarity index 96% rename from web/docs/guides/auth/auth-bitbucket.mdx rename to apps/reference/docs/guides/auth/auth-bitbucket.mdx index 774cd32c91d..6b1f4e96a9a 100644 --- a/web/docs/guides/auth/auth-bitbucket.mdx +++ b/apps/reference/docs/guides/auth/auth-bitbucket.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Bitbucket OAuth app diff --git a/web/docs/guides/auth/auth-discord.mdx b/apps/reference/docs/guides/auth/auth-discord.mdx similarity index 93% rename from web/docs/guides/auth/auth-discord.mdx rename to apps/reference/docs/guides/auth/auth-discord.mdx index e661bf752d8..8591a232d16 100644 --- a/web/docs/guides/auth/auth-discord.mdx +++ b/apps/reference/docs/guides/auth/auth-discord.mdx @@ -43,7 +43,12 @@ In the next step you require a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Discord Application @@ -76,6 +81,12 @@ const { user, session, error } = await supabase.auth.signIn({ }) ``` +:::note + +If you call `signIn()` when already logged in, Discord will prompt the user again for authorization. + +::: + Add this function which you can call from a button, link, or UI element. ```js diff --git a/web/docs/guides/auth/auth-email.mdx b/apps/reference/docs/guides/auth/auth-email.mdx similarity index 98% rename from web/docs/guides/auth/auth-email.mdx rename to apps/reference/docs/guides/auth/auth-email.mdx index 8edcca138e2..d776dc8e6af 100644 --- a/web/docs/guides/auth/auth-email.mdx +++ b/apps/reference/docs/guides/auth/auth-email.mdx @@ -96,7 +96,7 @@ async function signInWithEmail() { ```dart Future signInWithEmail() async { await supabase.auth.signIn( - email: 'example@email.com', + email: 'example@email.com', password: 'example-password' ); } diff --git a/web/docs/guides/auth/auth-facebook.mdx b/apps/reference/docs/guides/auth/auth-facebook.mdx similarity index 97% rename from web/docs/guides/auth/auth-facebook.mdx rename to apps/reference/docs/guides/auth/auth-facebook.mdx index d3fcccb5c06..c7a76ef1902 100644 --- a/web/docs/guides/auth/auth-facebook.mdx +++ b/apps/reference/docs/guides/auth/auth-facebook.mdx @@ -47,7 +47,12 @@ The next step requires a callback URI, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Set up FaceBook Login for your Facebook App diff --git a/web/docs/guides/auth/auth-github.mdx b/apps/reference/docs/guides/auth/auth-github.mdx similarity index 97% rename from web/docs/guides/auth/auth-github.mdx rename to apps/reference/docs/guides/auth/auth-github.mdx index c2d43ba9108..d171495bafb 100644 --- a/web/docs/guides/auth/auth-github.mdx +++ b/apps/reference/docs/guides/auth/auth-github.mdx @@ -48,7 +48,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Register a new OAuth application diff --git a/web/docs/guides/auth/auth-gitlab.mdx b/apps/reference/docs/guides/auth/auth-gitlab.mdx similarity index 96% rename from web/docs/guides/auth/auth-gitlab.mdx rename to apps/reference/docs/guides/auth/auth-gitlab.mdx index 5bcd2971232..adf4287ff03 100644 --- a/web/docs/guides/auth/auth-gitlab.mdx +++ b/apps/reference/docs/guides/auth/auth-gitlab.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create your GitLab Application diff --git a/web/docs/guides/auth/auth-google.mdx b/apps/reference/docs/guides/auth/auth-google.mdx similarity index 95% rename from web/docs/guides/auth/auth-google.mdx rename to apps/reference/docs/guides/auth/auth-google.mdx index aeb92d43f12..e3788c3f3aa 100644 --- a/web/docs/guides/auth/auth-google.mdx +++ b/apps/reference/docs/guides/auth/auth-google.mdx @@ -62,12 +62,17 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. -### Create your credentials +### Create your Google credentials -- Click `Credentials` at the left to go to the `Credentials` page +- Click `Credentials` at the left to go to the `Credentials` page on the Google Cloud Platform console. - Click `Create Credentials` near the top then select `OAuth client ID` - On the `Create OAuth client ID` page, select your application type. If you're not sure, choose `Web application`. - Fill in your app name. diff --git a/apps/reference/docs/guides/auth/auth-helpers/auth-ui.mdx b/apps/reference/docs/guides/auth/auth-helpers/auth-ui.mdx new file mode 100644 index 00000000000..f92a18f9322 --- /dev/null +++ b/apps/reference/docs/guides/auth/auth-helpers/auth-ui.mdx @@ -0,0 +1,297 @@ +--- +id: auth-ui +title: Auth UI +description: A prebuilt, customizable React component for authenticating users. +--- + +Auth UI is a pre-built React component for authenticating users. +It supports custom themes and extensible styles to match your brand and aesthetic. + + + +## Set up Auth UI + +Install the latest version of [supabase-js](/docs/reference/javascript/next/) and the Auth UI package: + +```bash +npm install @supabase/supabase-js@rc @supabase/auth-ui-react +``` + +### Import the Auth component + +Pass `supabaseClient` from `@supabase/supabase-js` as a prop to the component. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => +``` + +This renders the Auth component without any styling. +We recommend using one of the predefined themes to style the UI. +Import the theme you want to use and pass it to the `appearence.theme` prop. + +```diff js title="/src/index.js" +import { + Auth, + // highlight-next-line + ThemeSupa +} from '@supabase/auth-ui-react' + +const App = () => ( + +) +``` + +## Customization + +There are several ways to customize Auth UI: + +- Use one of the [predefined themes](#predefined-themes) that comes with Auth UI +- Extend a theme by [overriding the variable tokens](#override-themes) in a theme +- [Create your own theme](#create-theme) +- [Use your own CSS classes](#custom-css-classes) +- [Use inline styles](#custom-inline-styles) +- [Use your own labels](#custom-labels) + +### Predefined themes + +Auth UI comes with several themes to customize the appearance. Each predefined theme comes with at least two variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop. Import the theme you want to use and pass it to the `appearence.theme` prop. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +//highlight-next-line +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` + +:::info +Currently there is only one predefined theme available, but we plan to add more. +::: + +### Switch theme variations + +Auth UI comes with two theme variations: `default` and `dark`. You can switch between these themes with the `theme` prop. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` + +If you don't pass a value to `theme` it uses the `"default"` theme. You can pass `"dark"` to the theme prop to switch to the `dark` theme. If your theme has other variations, use the name of the variation in this prop. + +### Override themes + +Auth UI themes can be overridden using variable tokens. See the [list of variable tokens](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx). + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` + +If you created your own theme, you may not need to override any of the them. + +### Create your own theme {#create-theme} + +You can create your own theme by following the same structure within a `appearance.theme` property. +See the list of [tokens within a theme](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx). + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const customTheme = { + default: { + colors: { + brand: 'hsl(153 60.0% 53.0%)', + brandAccent: 'hsl(154 54.8% 45.1%)', + brandButtonText: 'white', + // .. + }, + dark: { + colors: { + brandButtonText: 'white', + defaultButtonBackground: '#2e2e2e', + defaultButtonBackgroundHover: '#3e3e3e', + //.. + }, + }, + // You can also add more theme variations with different names. + evenDarker: { + colors: { + brandButtonText: 'white', + defaultButtonBackground: '#1e1e1e', + defaultButtonBackgroundHover: '#2e2e2e', + //.. + }, + }, +} + +const App = () => ( + +) +``` + +You can swich between different variations of your theme with the ["theme" prop](#switch-theme-variations). + +### Custom CSS classes {#custom-css-classes} + +You can use custom CSS classes for the following elements: +`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` + +### Custom inline CSS {#custom-inline-styles} + +You can use custom CSS inline styles for the following elements: +`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` + +### Custom labels {#custom-labels} + +You can use custom labels with `localization.variables`. See the [list of labels](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/lib/Localization/en.json) that can be overwritten. + +```js title="/src/index.js" +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const App = () => ( + +) +``` diff --git a/apps/reference/docs/guides/auth/auth-helpers/index.mdx b/apps/reference/docs/guides/auth/auth-helpers/index.mdx new file mode 100644 index 00000000000..91247a76c9c --- /dev/null +++ b/apps/reference/docs/guides/auth/auth-helpers/index.mdx @@ -0,0 +1,55 @@ +--- +id: index +title: Auth Helpers +description: A collection of framework-specific Auth utilities for working with Supabase. +sidebar_label: Overview +--- + +import useBaseUrl from '@docusaurus/useBaseUrl' +import ButtonCard from '@site/src/components/ButtonCard' + +A collection of framework-specific Auth utilities for working with Supabase. + +
+
+ {/* Auth UI */} +
+ +
+ {/* Next.js */} +
+ +
+ {/* SvelteKit */} +
+ +
+
+
+ +## Status + +The Auth Helpers are in `beta`. They are usable in their current state, but it's likely that there will be breaking changes. + +## Additional Links + +- [Source code](https://github.com/supabase/auth-helpers) +- [Known bugs and issues](https://github.com/supabase/auth-helpers/issues) diff --git a/apps/reference/docs/guides/auth/auth-helpers/nextjs.mdx b/apps/reference/docs/guides/auth/auth-helpers/nextjs.mdx new file mode 100644 index 00000000000..193a970ebe9 --- /dev/null +++ b/apps/reference/docs/guides/auth/auth-helpers/nextjs.mdx @@ -0,0 +1,319 @@ +--- +id: nextjs +title: Supabase Auth with Next.js +description: Authentication helpers for Next.js API routes, middleware, and SSR. +sidebar_label: "Next.js" +--- + +This submodule provides convenience helpers for implementing user authentication in Next.js applications. + +## Installation + +Using [npm](https://npmjs.org): + +```sh +npm install @supabase/auth-helpers-nextjs + +# Main components and hooks for React based frameworks (optional) +npm install @supabase/auth-helpers-react +``` + +Using [yarn](https://yarnpkg.com/): + +```sh +yarn add @supabase/auth-helpers-nextjs + +# Main components and hooks for React based frameworks (optional) +yarn add @supabase/auth-helpers-react +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` + +- Next.js: `>=10` + +## Getting Started + +### Configuration + +Set up the following env vars. For local development you can set them in a `.env.local` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/nextjs/.env.local.example). + +```bash +# Find these in your Supabase project settings > API +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key +``` + +### Basic Setup + +- Create an `auth` directory under the `/pages/api/` directory. + +- Create a `[...supabase].js` file under the newly created `auth` directory. + +The path to your dynamic API route file would be `/pages/api/auth/[...supabase].js`. Populate that file as follows: + +```js +import { handleAuth } from '@supabase/auth-helpers-nextjs' + +export default handleAuth({ logout: { returnTo: '/' } }) +``` + +Executing `handleAuth()` creates the following route handlers under the hood that perform different parts of the authentication flow: + +- `/api/auth/callback`: The `UserProvider` forwards the session details here every time `onAuthStateChange` fires on the client side. This is needed to set up the cookies for your application so that SSR works seamlessly. + +- `/api/auth/user`: You can fetch user profile information in JSON format. + +- `/api/auth/logout`: Your Next.js application logs out the user. You can optionally pass a `returnTo` parameter to return to a custom relative URL after logout, eg `/api/auth/logout?returnTo=/login`. This will overwrite the logout `returnTo` option specified `handleAuth()` + +Wrap your `pages/_app.js` component with the `UserProvider` component: + +```jsx +// pages/_app.js +import React from 'react' +import { UserProvider } from '@supabase/auth-helpers-react' +import { supabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function App({ Component, pageProps }) { + return ( + + + + ) +} +``` + +You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined. + +## Client-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `# @supabase/auth-helpers-nextjs` and only run your query once the user is defined client-side in the `useUser()` hook: + +```js +import { Auth } from '@supabase/ui' +import { useUser } from '@supabase/auth-helpers-react' +import { supabaseClient } from '@supabase/auth-helpers-nextjs' +import { useEffect, useState } from 'react' + +const LoginPage = () => { + const { user, error } = useUser() + const [data, setData] = useState() + + useEffect(() => { + async function loadData() { + const { data } = await supabaseClient.from('test').select('*') + setData(data) + } + // Only run query once user is logged in. + if (user) loadData() + }, [user]) + + if (!user) + return ( + <> + {error &&

{error.message}

} + + + ) + + return ( + <> + +

user:

+
{JSON.stringify(user, null, 2)}
+

client-side data fetching with RLS

+
{JSON.stringify(data, null, 2)}
+ + ) +} + +export default LoginPage +``` + +### Server-side rendering (SSR) - withPageAuth + +If you wrap your `getServerSideProps` with `withPageAuth` your props object will be augmented with the user object. + +```js +// pages/profile.js +import { withPageAuth } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }) { + return
Hello {user.name}
+} + +export const getServerSideProps = withPageAuth({ redirectTo: '/login' }) +``` + +If there is no authenticated user, they will be redirect to your home page, unless you specify the `redirectTo` option. + +You can pass in your own `getServerSideProps` method, the props returned from this will be merged with the +user props. You can also access the user session data by calling `getUser` inside of this method, eg: + +```js +// pages/protected-page.js +import { withPageAuth, getUser } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, customProp }) { + return
Protected content
+} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/foo', + async getServerSideProps(ctx) { + // Access the user object + const { user, accessToken } = await getUser(ctx) + return { props: { email: user?.email } } + }, +}) +``` + +### Server-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to inject the request context into the supabase client: + +```js +import { + User, + withPageAuth, + supabaseServerClient, +} from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ + user, + data, +}: { + user: User, + data: any, +}) { + return ( + <> +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/', + async getServerSideProps(ctx) { + // Run queries with RLS on the server + const { data } = await supabaseServerClient(ctx).from('test').select('*') + return { props: { data } } + }, +}) +``` + +### Server-side data fetching to OAuth APIs using `provider_token` + +When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted as an HTTPOnly cookie upon logging in to enabled usage on the server side. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. In the following example, we fetch the user's full profile from the third-party API during SSR using their id and auth token: + +```js +import { User, withPageAuth, getUser } from '@supabase/auth-helpers-nextjs' + +interface Profile { + /* ... */ +} + +export default function ProtectedPage({ + user, + data, +}: { + user: User, + profile: Profile, +}) { + return
Protected content
+} + +export const getServerSideProps = withPageAuth({ + redirectTo: '/', + async getServerSideProps(ctx) { + // Retrieve provider_token from cookies + const provider_token = ctx.req.cookies['sb-provider-token'] + // Get logged in user's third-party id from metadata + const { user } = await getUser(ctx) + const userId = user?.user_metadata.provider_id + const profile: Profile = await ( + await fetch(`https://api.example.com/users/${userId}`, { + method: 'GET', + headers: { + Authorization: `Bearer ${provider_token}`, + }, + }) + ).json() + return { props: { profile } } + }, +}) +``` + +## Protecting API routes + +Wrap an API Route to check that the user has a valid session. If they're not logged in the handler will return a +401 Unauthorized. + +```js +// pages/api/protected-route.js +import { + withApiAuth, + supabaseServerClient, +} from '@supabase/auth-helpers-nextjs' + +export default withApiAuth(async function ProtectedRoute(req, res) { + // Run queries with RLS on the server + const { data } = await supabaseServerClient({ req, res }) + .from('test') + .select('*') + res.json(data) +}) +``` + +If you visit `/api/protected-route` without a valid session cookie, you will get a 401 response. + +## Protecting routes with [Nextjs Middleware](https://nextjs.org/docs/middleware) + +As an alternative to protecting individual pages using `getServerSideProps` with `withPageAuth`, `withMiddlewareAuth` can be used from inside a `_middleware` file to protect an entire directory. In the following example, all requests to `/protected/*` will check whether a user is signed in, if successful the request will be forwarded to the destination route, otherwise the user will be redirected to `/login` (defaults to: `/`) with a 307 Temporary Redirect response status: + +```ts +// pages/protected/_middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/middleware' + +export const middleware = withMiddlewareAuth({ redirectTo: '/login' }) +``` + +It is also possible to add finer granularity based on the user logged in. I.e. you can specify a promise to determine if a specific user has permission or not. + +```ts +// pages/protected/_middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/dist/middleware' + +export const middleware = withMiddlewareAuth({ + redirectTo: '/login', + authGuard: { + isPermitted: async (user) => user.email?.endsWith('@example.com') ?? false, + redirectTo: '/insufficient-permissions', + }, +}) +``` + +## Migrating from @supabase/supabase-auth-helpers to @supabase/auth-helpers + +This is a step by step guide on migrating away from the `@supabase/supabase-auth-helpers` to the newly released `@supabase/auth-helpers`. + +1. Install `@supabase/supabase-js`, `@supabase/auth-helpers-nextjs` and `@supabase/auth-helpers-react` libraries from npm. +2. Replace all imports of `@supabase/supabase-auth-helpers/nextjs` in your project with `@supabase/auth-helpers-nextjs`. +3. Replace all imports of `@supabase/supabase-auth-helpers/react` in your project with `@supabase/auth-helpers-react`. +4. Replace all instances of `withAuthRequired` in any of your NextJS pages with `withPageAuth`. +5. Replace all instances of `withAuthRequired` in any of your NextJS API endpoints with `withApiAuth`. +6. Uninstall `@supabase/supabase-auth-helpers`. + +## Additional Links + +- [Auth Helpers Source code](https://github.com/supabase/auth-helpers) +- [Next.js example](https://github.com/supabase/auth-helpers/tree/main/examples/nextjs) diff --git a/apps/reference/docs/guides/auth/auth-helpers/sveltekit.mdx b/apps/reference/docs/guides/auth/auth-helpers/sveltekit.mdx new file mode 100644 index 00000000000..849c9c5a771 --- /dev/null +++ b/apps/reference/docs/guides/auth/auth-helpers/sveltekit.mdx @@ -0,0 +1,309 @@ +--- +id: sveltekit +title: Supabase Auth with SvelteKit +description: Convenience helpers for implementing user authentication in SvelteKit. +sidebar_label: SvelteKit +--- + +This submodule provides convenience helpers for implementing user authentication in [SvelteKit](https://kit.svelte.dev/) applications. + +## Installation + +Using [npm](https://npmjs.org): + +```sh +npm install @supabase/auth-helpers-sveltekit + +# Main component for Svelte based frameworks (optional but recommended) +npm install @supabase/auth-helpers-svelte +``` + +Using [yarn](https://yarnpkg.com/): + +```sh +yarn add @supabase/auth-helpers-sveltekit + +# Main component for Svelte based frameworks (optional but recommended) +yarn add @supabase/auth-helpers-svelte +``` + +This library supports the following tooling versions: + +- Node.js: `^16.15.0` + +## Getting Started + +### Configuration + +Set up the fillowing env vars. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/sveltekit/.env.example). + +```bash +# Find these in your Supabase project settings > API +VITE_SUPABASE_URL=https://your-project.supabase.co +VITE_SUPABASE_ANON_KEY=your-anon-key +``` + +### SupabaseClient and SupaAuthHelper component setup + +We will start off by creating a `db.ts` file inside of our `src/lib` directory. Now lets instantiate our `supabaseClient` by using our `createSupabaseClient` function from the `@supabase/auth-helpers-sveltekit` library. + +```ts +// src/lib/db.ts +import { createSupabaseClient } from '@supabase/auth-helpers-sveltekit' + +const { supabaseClient } = createSupabaseClient( + import.meta.env.VITE_SUPABASE_URL as string, + import.meta.env.VITE_SUPABASE_ANON_KEY as string +) + +export { supabaseClient } +``` + +Edit your `__layout.svelte` file and add import the `SupaAuthHelper` component, the `supabaseClient` we just instantiated and the `session` store. + +```html +// src/routes/__layout.svelte + + + + + +``` + +### Hooks setup + +Our `hooks.ts` file is where the heavy lifting of this library happens, we need to import our function to handle the sign in, signing out and cookie creation phase. we can import all the hooks using `handleAuth` function and destructure its returned data. + +```ts +// src/hooks.ts +import { handleAuth } from '@supabase/auth-helpers-sveltekit' +import type { GetSession, Handle } from '@sveltejs/kit' +import { sequence } from '@sveltejs/kit/hooks' + +export const handle: Handle = sequence(...handleAuth()) + +export const getSession: GetSession = async (event) => { + const { user, accessToken, error } = event.locals + return { + user, + accessToken, + error, + } +} +``` + +These will create the handlers under the hood that perform different parts of the authentication flow: + +- `/api/auth/callback`: The `UserHelper` forwards the session details here every time `onAuthStateChange` fires on the client side. This is needed to set up the cookies for your application so that SSR works seamlessly. +- `/api/auth/user`: You can fetch user profile information in JSON format. +- `/api/auth/logout`: You can logout the user. + +### Typings + +In order to get the most out of TypeScript and its intellisense, you should import our types into the `app.d.ts` type definition file that comes with your SvelteKit project. + +```ts +// src/app.d.ts +/// +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare namespace App { + interface UserSession { + user: import('@supabase/supabase-js').User + accessToken?: string + } + interface Locals extends UserSession { + error: import('@supabase/supabase-js').ApiError + } + + interface Session extends UserSession {} // interface Platform {} // interface Stuff {} +} +``` + +### Signing out + +This library has provided a dedicated endpoint for you to use to sign a user out. This endpoint will sign the user out of the Gotrue server, clear the cookies that were set when the user logged in and redirect the user to a configurable path. + +The logout handler endpoint is `/api/auth/logout`, this will take a `GET` request which means it can be used as the href for a normal `a` tag in your html. + +```html +Sign out +``` + +### Logout handler configuration + +In your `src/hooks.ts` file the logout handler is already setup and you can configure the redirect path from here. + +> By default the redirect path after logging out will be `/`. + +```ts +export const handle = sequence( + ...handleAuth({ + logout: { returnTo: '/auth/signin' }, + }) +) +``` + +### Basic Setup + +You can now determine if a user is authenticated on the client-side by checking that the `user` object returned by the `$session` store is defined. + +```html +// example + + +{#if !$session.user} +

I am not logged in

+{:else} +

Welcome {$session.user.email}

+

I am logged in!

+{/if} +``` + +## Client-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `@supabase/auth-helpers-sveltekit` and only run your query once the user is defined client-side in the `$session`: + +```html + + +{#if !$session.user} + {#if $error} +

{$error.message}

+ {/if} +

{$isLoading ? `Loading...` : `Loaded!`}

+ +{:else} + Sign out +

user:

+
{JSON.stringify($session.user, null, 2)}
+

client-side data fetching with RLS

+
{JSON.stringify(loadedData, null, 2)}
+{/if} +``` + +### Server-side data fetching with RLS + +For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to inject the request context into the supabase client: + +```html + + + +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+``` + +```ts +// src/routes/profile.ts +import { + supabaseServerClient, + withApiAuth, +} from '@supabase/auth-helpers-sveltekit' +import type { RequestHandler } from './__types/profile' + +interface TestTable { + id: string + created_at: string +} + +interface GetOutput { + user: User + data: TestTable[] +} + +export const GET: RequestHandler = async ({ locals }) => + withApiAuth( + { + redirectTo: '/', + user: locals.user, + }, + async () => { + const { data } = await supabaseServerClient(session.accessToken) + .from('test') + .select('*') + + return { + body: { + user: locals.user, + data, + }, + } + } + ) +``` + +## Protecting API routes + +Wrap an API Route to check that the user has a valid session. If they're not logged in the handler will return a +303 and redirect header. + +```ts +// src/routes/api/protected-route.ts +import { + supabaseServerClient, + withApiAuth, +} from '@supabase/auth-helpers-sveltekit' +import type { RequestHandler } from './__types/protected-route' + +interface TestTable { + id: string + created_at: string +} + +interface GetOutput { + data: TestTable[] +} + +export const GET: RequestHandler = async ({ locals, request }) => + withApiAuth({ user: locals.user }, async () => { + // Run queries with RLS on the server + const { data } = await supabaseServerClient(request) + .from('test') + .select('*') + + return { + status: 200, + body: { data }, + } + }) +``` + +If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response. + +## Additional Links + +- [Auth Helpers Source code](https://github.com/supabase/auth-helpers) +- [SvelteKit example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit) +- [SvelteKit Email/Password example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit-email-password) +- [SvelteKit Magiclink example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit-magic-link) diff --git a/web/docs/guides/auth/auth-keycloak.mdx b/apps/reference/docs/guides/auth/auth-keycloak.mdx similarity index 88% rename from web/docs/guides/auth/auth-keycloak.mdx rename to apps/reference/docs/guides/auth/auth-keycloak.mdx index ac5c41dbf19..39d1eb96196 100644 --- a/web/docs/guides/auth/auth-keycloak.mdx +++ b/apps/reference/docs/guides/auth/auth-keycloak.mdx @@ -11,7 +11,7 @@ To enable Keycloak Auth for your project, you need to set up an Keycloak OAuth a ## Overview -To get started with Keycloak, you can run it in a docker container with: `docker run -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8080:8080 jboss/keycloak:latest` +To get started with Keycloak, you can run it in a docker container with: `docker run -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8080:8080 jboss/keycloak:latest` This guide will be assuming that you are running keycloak in a docker container as described in the command above. @@ -28,13 +28,13 @@ Keycloak OAuth consists of five broad steps: ### Access your Keycloak Admin console -- Login by visiting [`http://localhost:8080`](http://localhost:8080) and clicking on "Administration Console". +- Login by visiting [`http://localhost:8080`](http://localhost:8080) and clicking on "Administration Console". ### Create a Keycloak Realm - Once you've logged in to the Keycloak console, you can add a realm from the side panel. The default realm should be named "Master". -- After you've added a new realm, you can retrieve the `issuer` from the "OpenID Endpoint Configuration" endpoint. The `issuer` will be used as the `Keycloak URL`. -- You can find this endpoint from the realm settings under the "General Tab" or visit [`http://localhost:8080/auth/realms/my_realm_name/.well-known/openid-configuration`](http://localhost:8080/auth/realms/my_realm_name/.well-known/openid-configuration) +- After you've added a new realm, you can retrieve the `issuer` from the "OpenID Endpoint Configuration" endpoint. The `issuer` will be used as the `Keycloak URL`. +- You can find this endpoint from the realm settings under the "General Tab" or visit [`http://localhost:8080/realms/my_realm_name/.well-known/openid-configuration`](http://localhost:8080/realms/my_realm_name/.well-known/openid-configuration) ![Add a Keycloak Realm.](/img/guides/auth-keycloak/keycloak-create-realm.png) @@ -47,6 +47,7 @@ The "Client ID" of the created client will serve as the `client_id` when you mak ### Client Settings After you've created the client successfully, ensure that you set the following settings: + 1. The "Client Protocol" should be set to "openid-connect". 2. The "Access Type" should be set to "confidential". 3. The "Valid Redirect URIs" should be set to: `https://.supabase.co/auth/v1/callback`. @@ -57,7 +58,7 @@ After you've created the client successfully, ensure that you set the following ### Obtain the Client Secret This will serve as the `client_secret` when you make API calls to authenticate the user. -Under the "Credentials" tab, the `Secret` value will be used as the `client secret`. +Under the "Credentials" tab, the `Secret` value will be used as the `client secret`. ![Obtain the client secret](/img/guides/auth-keycloak/keycloak-client-secret.png) @@ -89,7 +90,7 @@ async function signout() { } ``` -## Resources +## Resources - You can find the keycloak openid endpoint configuration under the realm settings. -![Keycloak OpenID Endpoint Configuration](/img/guides/auth-keycloak/keycloak-openid-endpoint-config.png) + ![Keycloak OpenID Endpoint Configuration](/img/guides/auth-keycloak/keycloak-openid-endpoint-config.png) diff --git a/web/docs/guides/auth/auth-linkedin.mdx b/apps/reference/docs/guides/auth/auth-linkedin.mdx similarity index 91% rename from web/docs/guides/auth/auth-linkedin.mdx rename to apps/reference/docs/guides/auth/auth-linkedin.mdx index b7031776217..db857f6fed4 100644 --- a/web/docs/guides/auth/auth-linkedin.mdx +++ b/apps/reference/docs/guides/auth/auth-linkedin.mdx @@ -14,7 +14,7 @@ To enable LinkedIn Auth for your project, you need to set up a LinkedIn OAuth ap Setting up LinkedIn logins for your application consists of 3 parts: - Create and configure a LinkedIn Project and App on the [LinkedIn Developer Dashboard](https://www.linkedin.com/developers/apps). -- Add your LinkedIn `API Key` and `API Secret Key` to your [Supabase Project](https://app.supabase.com). +- Add your LinkedIn `client_id` and `client_secret` to your [Supabase Project](https://app.supabase.com). - Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js). ## Steps @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a LinkedIn OAuth app @@ -60,7 +65,7 @@ The next step requires a callback URL, which looks like this: - Click `Settings` from the list to go to the `Authentication Settings` page. - Enter the final (hosted) URL of your app under `Site URL` (this is important). - Under `External OAuth Providers` turn `LinkedIn Enabled` to ON. -- Enter your `API Key` (`client_id`) and `API Secret Key` (`client_secret`) saved in the previous step. +- Enter your `client_id` and `client_secret` saved in the previous step. - Click `Save`. ### Add login code to your client app diff --git a/web/docs/guides/auth/auth-magic-link.mdx b/apps/reference/docs/guides/auth/auth-magic-link.mdx similarity index 100% rename from web/docs/guides/auth/auth-magic-link.mdx rename to apps/reference/docs/guides/auth/auth-magic-link.mdx diff --git a/web/docs/guides/auth/auth-messagebird.mdx b/apps/reference/docs/guides/auth/auth-messagebird.mdx similarity index 99% rename from web/docs/guides/auth/auth-messagebird.mdx rename to apps/reference/docs/guides/auth/auth-messagebird.mdx index dd806ecb6b7..b67591f0b73 100644 --- a/web/docs/guides/auth/auth-messagebird.mdx +++ b/apps/reference/docs/guides/auth/auth-messagebird.mdx @@ -40,7 +40,7 @@ This is the number that will be receiving the SMS OTPs. ![Get your API Keys](/img/guides/auth-messagebird/2.png) -Navigate to the [dashboard settings](https://dashboard.messagebird.com/en/settings/sms) to set the default originator. The messagebird originator is the name or number from which the message is sent. +Navigate to the [dashboard settings](https://dashboard.messagebird.com/en/settings/sms) to set the default originator. The messagebird originator is the name or number from which the message is sent. For more information, you can refer to the messagebird article on choosing an originator [here](https://support.messagebird.com/hc/en-us/articles/115002628665-Choosing-an-originator) ![Set the default originator](/img/guides/auth-messagebird/3.png) @@ -59,9 +59,10 @@ You should see an option to enable Phone Signup. Toggle it on, and copy the 2 values over from the messagebird dashboard. Click save. Note: If you use the Test API Key, the OTP will not be delivered to the mobile number specified but messagebird will log the response in the dashboard. -If the Live API Key is used instead, the OTP will be delivered and there will be a deduction in your free credits. +If the Live API Key is used instead, the OTP will be delivered and there will be a deduction in your free credits. + Plugin MessageBird credentials Now the backend should be setup, we can proceed to add our client-side code! diff --git a/web/docs/guides/auth/auth-notion.mdx b/apps/reference/docs/guides/auth/auth-notion.mdx similarity index 97% rename from web/docs/guides/auth/auth-notion.mdx rename to apps/reference/docs/guides/auth/auth-notion.mdx index 44a6464c03d..1f615f76bbd 100644 --- a/web/docs/guides/auth/auth-notion.mdx +++ b/apps/reference/docs/guides/auth/auth-notion.mdx @@ -34,6 +34,7 @@ Setting up Notion logins for your application consists of 3 parts: ![notion.so](/img/guides/auth-notion/notion-developer.png) ### Add the redirect uri + - After selecting "Public integration", you should see an option to add "Redirect URIs". ![notion.so](/img/guides/auth-notion/notion-redirect-uri.png) @@ -49,7 +50,12 @@ You can retrieve the redirect uri with the following steps: Your redirect uri should look like the following: `https://.supabase.co/auth/v1/callback` ### Add your Notion credentials into your Supabase Project diff --git a/web/docs/guides/auth/auth-slack.mdx b/apps/reference/docs/guides/auth/auth-slack.mdx similarity index 93% rename from web/docs/guides/auth/auth-slack.mdx rename to apps/reference/docs/guides/auth/auth-slack.mdx index 75c4e4f0feb..c9568eaa593 100644 --- a/web/docs/guides/auth/auth-slack.mdx +++ b/apps/reference/docs/guides/auth/auth-slack.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Slack OAuth app @@ -73,7 +78,7 @@ Under `Redirect URLs`: - Click `Settings` from the list to go to the `Authentication Settings` page. - Enter the final (hosted) URL of your app under `Site URL` (this is important). - Under `External OAuth Providers` turn `Slack Enabled` to ON. -- Enter your `API Key` (`client_id`) and `API Secret Key` (`client_secret`) saved in the previous step. +- Enter your `Client ID` (`client_id`) and `Client Secret` (`client_secret`) saved in the previous step. - Click `Save`. ### Add login code to your client app diff --git a/web/docs/guides/auth/auth-spotify.mdx b/apps/reference/docs/guides/auth/auth-spotify.mdx similarity index 93% rename from web/docs/guides/auth/auth-spotify.mdx rename to apps/reference/docs/guides/auth/auth-spotify.mdx index f27517b4b0e..c617021e79b 100644 --- a/web/docs/guides/auth/auth-spotify.mdx +++ b/apps/reference/docs/guides/auth/auth-spotify.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Spotify OAuth app @@ -68,7 +73,7 @@ Under `Redirect URIs`: - Click `Settings` from the list to go to the `Authentication Settings` page. - Enter the final (hosted) URL of your app under `Site URL` (this is important). - Under `External OAuth Providers` turn `Spotify Enabled` to ON. -- Enter your `API Key` (`client_id`) and `API Secret Key` (`client_secret`) saved in the previous step. +- Enter your `Client ID` (`client_id`) and `Client Secret` (`client_secret`) saved in the previous step. - Click `Save`. ### Add login code to your client app diff --git a/web/docs/guides/auth/auth-twilio.mdx b/apps/reference/docs/guides/auth/auth-twilio.mdx similarity index 96% rename from web/docs/guides/auth/auth-twilio.mdx rename to apps/reference/docs/guides/auth/auth-twilio.mdx index ba9ac6fec27..685f6554746 100644 --- a/web/docs/guides/auth/auth-twilio.mdx +++ b/apps/reference/docs/guides/auth/auth-twilio.mdx @@ -30,15 +30,14 @@ What you'll need: ## Video - +
+ +
## Steps @@ -89,7 +88,7 @@ The SMS message sent to a phone containing an OTP code can be customized. This i Go to Auth > Templates page in the Supabase dashboard (https://app.supabase.com/project/YOUR-PROJECT-REF/auth/templates). -Use the variable `.Code` in the template to display the OTP code. Here's an example in the SMS template. +Use the variable `.Code` in the template to display the OTP code. Here's an example in the SMS template. ![example in the SMS template](/img/guides/auth-twilio/9.png) diff --git a/web/docs/guides/auth/auth-twitch.mdx b/apps/reference/docs/guides/auth/auth-twitch.mdx similarity index 97% rename from web/docs/guides/auth/auth-twitch.mdx rename to apps/reference/docs/guides/auth/auth-twitch.mdx index 4c5b5519598..ef76d915913 100644 --- a/web/docs/guides/auth/auth-twitch.mdx +++ b/apps/reference/docs/guides/auth/auth-twitch.mdx @@ -44,7 +44,12 @@ In the next step you require a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Twitch Application diff --git a/web/docs/guides/auth/auth-twitter.mdx b/apps/reference/docs/guides/auth/auth-twitter.mdx similarity index 97% rename from web/docs/guides/auth/auth-twitter.mdx rename to apps/reference/docs/guides/auth/auth-twitter.mdx index 537137ea5ab..d5f5726d756 100644 --- a/web/docs/guides/auth/auth-twitter.mdx +++ b/apps/reference/docs/guides/auth/auth-twitter.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Twitter OAuth app diff --git a/web/docs/guides/auth/auth-vonage.mdx b/apps/reference/docs/guides/auth/auth-vonage.mdx similarity index 99% rename from web/docs/guides/auth/auth-vonage.mdx rename to apps/reference/docs/guides/auth/auth-vonage.mdx index 109101c6cb5..d1a71db6c2b 100644 --- a/web/docs/guides/auth/auth-vonage.mdx +++ b/apps/reference/docs/guides/auth/auth-vonage.mdx @@ -271,4 +271,4 @@ The user does not have a password therefore will need to sign in via this method - [Vonage Signup](https://dashboard.nexmo.com/sign-up) - [Supabase Dashboard](https://app.supabase.com) -- [Supabase Row Level Security](/docs/guides/auth#row-level-security) \ No newline at end of file +- [Supabase Row Level Security](/docs/guides/auth#row-level-security) diff --git a/web/docs/guides/auth/auth-workos.mdx b/apps/reference/docs/guides/auth/auth-workos.mdx similarity index 87% rename from web/docs/guides/auth/auth-workos.mdx rename to apps/reference/docs/guides/auth/auth-workos.mdx index 5a4b1abb306..9e2ef7c79e7 100644 --- a/web/docs/guides/auth/auth-workos.mdx +++ b/apps/reference/docs/guides/auth/auth-workos.mdx @@ -58,34 +58,38 @@ You can pick between any one of the many identity providers that WorkOS supports - Enter the `Client ID`, `Secret`, and `WorkOS URL` saved in the previous steps. The ``WorkOS URL` setting should be set to https://api.workos.com/ - Click `Save` - - ### Add login code to your client app The JavaScript client code is documented in the [Supabase OAuth Reference](/docs/reference/javascript/auth-signin#sign-in-using-third-party-providers). Note that you only need to include one of the three parameters: `connection`, `organization`, and `provider`. You can refer to the [WorkOS Documentation](https://workos.com/docs/reference/sso/authorize/) to learn more about the different methods. ```js -const { user, session, error } = await supabase.auth.signIn({ - provider: 'workos', -}, { - connection: "", - organization: "" -}) +const { user, session, error } = await supabase.auth.signIn( + { + provider: 'workos', + }, + { + connection: '', + organization: '', + } +) ``` Add a function which you can call from a button, link, or UI element. ```js async function signInWithWorkOS() { - const { user, session, error } = await supabase.auth.signIn({ - provider: 'workos', - }, { - connection: "", - organization: "" - }) + const { user, session, error } = await supabase.auth.signIn( + { + provider: 'workos', + }, + { + connection: '', + organization: '', + } + ) } ``` diff --git a/web/docs/guides/auth/auth-zoom.mdx b/apps/reference/docs/guides/auth/auth-zoom.mdx similarity index 96% rename from web/docs/guides/auth/auth-zoom.mdx rename to apps/reference/docs/guides/auth/auth-zoom.mdx index 3d2e3b7b478..cab2ad3e6f5 100644 --- a/web/docs/guides/auth/auth-zoom.mdx +++ b/apps/reference/docs/guides/auth/auth-zoom.mdx @@ -39,7 +39,12 @@ The next step requires a callback URL, which looks like this: - Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`. ### Create a Zoom Oauth App diff --git a/web/docs/guides/auth/managing-user-data.mdx b/apps/reference/docs/guides/auth/managing-user-data.mdx similarity index 91% rename from web/docs/guides/auth/managing-user-data.mdx rename to apps/reference/docs/guides/auth/managing-user-data.mdx index d0affd2a189..ee6461042f6 100644 --- a/web/docs/guides/auth/managing-user-data.mdx +++ b/apps/reference/docs/guides/auth/managing-user-data.mdx @@ -4,7 +4,7 @@ title: Managing User Data description: Securing your user data with Row Level Security. --- -For security purposes, the `auth` schema is not exposed on the auto-generated API. +For security purposes, the `auth` schema is not exposed on the auto-generated API. Even though Supabase provides an `auth.users` table, it can be helpful to create tables in the `public` schema for storing user data that you want to access via the API. @@ -26,10 +26,9 @@ create table public.profiles ( alter table public.profiles enable row level security; ``` - ## Public access -Since Row Level Security is enabled, this table is accessible via the API but no data will be returned unless we set up some Policies. +Since Row Level Security is enabled, this table is accessible via the API but no data will be returned unless we set up some Policies. If we wanted the data to be _readable_ by everyone but only allow logged-in users to update their own data, the Policies would look like this: ```sql @@ -64,7 +63,7 @@ const { data } = await supabase .from('profiles') .select('id, username, avatar_url, website') -// After the user is logged in, this will only return +// After the user is logged in, this will only return // the logged-in user's data - in this case a single row const { error } = await supabase.auth.signIn({ email }) const { data: profile } = await supabase @@ -72,27 +71,26 @@ const { data: profile } = await supabase .select('id, username, avatar_url, website') ``` -## Bypassing Row Level Security +## Bypassing Row Level Security -If you need to fetch a full list of user profiles, we supply a `service_key` which you can use with your API and Client Libraries to bypass Row Level Security. +If you need to fetch a full list of user profiles, we supply a `service_key` which you can use with your API and Client Libraries to bypass Row Level Security. Make sure you _NEVER_ expose this publicly. But it can be used on the server-side to fetch all of the profiles. - ## Advanced techniques ### Using triggers -If you want to add a row to your `public.profiles` table every time a user signs up, you can use triggers. +If you want to add a row to your `public.profiles` table every time a user signs up, you can use triggers. If the trigger fails however, it could block the user sign ups - so make sure that the code is well-tested. For example: ```sql -- inserts a row into public.users -create function public.handle_new_user() -returns trigger -language plpgsql +create function public.handle_new_user() +returns trigger +language plpgsql security definer set search_path = public as $$ begin diff --git a/web/docs/guides/auth/row-level-security.mdx b/apps/reference/docs/guides/auth/row-level-security.mdx similarity index 95% rename from web/docs/guides/auth/row-level-security.mdx rename to apps/reference/docs/guides/auth/row-level-security.mdx index c75735384e0..a103c6a676e 100644 --- a/web/docs/guides/auth/row-level-security.mdx +++ b/apps/reference/docs/guides/auth/row-level-security.mdx @@ -8,15 +8,14 @@ When you need granular authorization rules, nothing beats PostgreSQL's [Row Leve [Policies](https://www.postgresql.org/docs/current/sql-createpolicy.html) are PostgreSQL's rule engine. They are incredibly powerful and flexible, allowing you to write complex SQL rules which fit your unique business needs. - +
+ +
## Policies @@ -46,6 +45,10 @@ Supabase provides you with a few easy functions that you can use with your polic Returns the ID of the user making the request. +### `auth.jwt()` + +Returns the JWT of the user making the request. + ### `auth.role()` :::caution @@ -74,6 +77,12 @@ using ( ### `auth.email()` +:::caution + +Deprecated. Use `auth.jwt() ->> 'email'` instead. + +::: + Returns the email of the user making the request. ## Examples @@ -229,7 +238,7 @@ alter table leaderboard create policy "Only Blizzard staff can update leaderboard" on leaderboard for update using ( - right(auth.email(), 13) = '@blizzard.com' + right(auth.jwt() ->> 'email', 13) = '@blizzard.com' ); ``` diff --git a/apps/reference/docs/guides/cli.mdx b/apps/reference/docs/guides/cli.mdx new file mode 100644 index 00000000000..0d0dd99be0e --- /dev/null +++ b/apps/reference/docs/guides/cli.mdx @@ -0,0 +1,110 @@ +--- +id: cli +title: Supabase CLI +description: The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform. +sidebar_label: Overview +toc_max_heading_level: 2 +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform. +You can also use the CLI to manage your Supabase projects, handle database migrations and CI/CD workflows, and generate types directly from your database schema. + +## Installation + + + + +Install the CLI with [Homebrew](https://brew.sh): + +```sh +brew install supabase/tap/supabase +``` + + + + + +Install the CLI with [Scoop](https://scoop.sh): + +```powershell +scoop bucket add supabase https://github.com/supabase/scoop-bucket.git +scoop install supabase +``` + + + + + +The CLI is available through [Homebrew](https://brew.sh) and Linux packages. + +### Homebrew + +```sh +brew install supabase/tap/supabase +``` + +### Linux packages + +Linux packages are provided in [Releases](https://github.com/supabase/cli/releases). +To install, download the `.apk`/`.deb`/`.rpm` file depending on your package manager +and run one of the following: + +- `sudo apk add --allow-untrusted <...>.apk` +- `sudo dpkg -i <...>.deb` +- `sudo rpm -i <...>.rpm` + + + + +## Updates + +When a new [version](https://github.com/supabase/cli/releases) is released, you can update the CLI using the same methods. + + + + +```sh +brew upgrade supabase +``` + + + + + +```powershell +scoop update supabase +``` + + + + + +```sh +brew upgrade supabase +``` + + + + +## See also + +- [Supabase CLI Reference](/docs/reference/cli/usage) +- [Local Development](/docs/guides/cli/local-development) +- [CI/CD Workflow](/docs/guides/cli/cicd-workflow) diff --git a/apps/reference/docs/guides/cli/cicd-workflow.mdx b/apps/reference/docs/guides/cli/cicd-workflow.mdx new file mode 100644 index 00000000000..875d240c300 --- /dev/null +++ b/apps/reference/docs/guides/cli/cicd-workflow.mdx @@ -0,0 +1,385 @@ +--- +id: cicd-workflow +title: CI / CD Workflow +description: How to deploy Supabase schema changes with a CI / CD pipeline. +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +## Overview + +The Supabase CLI also functions as a database migrations tool. In this guide, we will show you how to setup your local Supabase development environment that integrates with GitHub Action to automatically test and release schema changes to staging and production Supabase projects. + +- `develop` branch tracks staging +- `main` branch tracks production + +![Workflow overview](/img/guides/cli/workflow.png) + +Before you start, here are some prerequisites: + +- [Install the Supabase CLI](/docs/guides/cli) +- Create a Supabase project +- Initialise a local Git repository + +You can use your existing Supabase project and Git repository to follow this guide. Otherwise, you can [create a new project](https://app.supabase.com/?next=new-project) and set up an empty Git repository. + +## Setting up a project + +The first step is to set up your local repository with the Supabase CLI. You can do this by running: + +```bash +supabase init +``` + +You should see that a new `supabase` directory is created. Then you need to link your local repository with your Supabase project: + +```sql +supabase login +supabase link --project-ref $PROJECT_ID +``` + +You can get your `$PROJECT_ID` from your project’s dashboard URL: + +``` +https://app.supabase.com/project/ +``` + +If you’re using an existing Supabase project, you might have made schema changes through the dashboard. You need to pull these changes before making local schema changes from the CLI. You can do this by running: + +```sql +supabase db remote commit +``` + +This command creates a new migration in `supabase/migrations/_remote_commit.sql` that reflects all the schema changes you might have made beforehand. + +Now commit your local changes to Git and run the local development setup: + +```sql +supabase start +``` + +You are now ready to develop schema changes locally and create your first migration 🎉 + +## Creating a new migration + +There are two ways to make schema changes in a version controlled way. + +1. Write DDL statements manually into a migration file +2. Make changes through Studio UI and auto generate a schema diff + +For this guide, we will create an `employees` table using the schema below. + +```sql +create table public.employees ( + id integer primary key generated always as identity, + name text +); +``` + +### Manual migration + +![Manual migration](/img/guides/cli/diff-manual.png) + +The first step is to create a new migration script. You can do this by running: + +```bash +supabase migration new new_employee +``` + +You should see that a new file `supabase/migrations/_new_employee.sql` is created. You can then write any DDL statements in this script using a text editor. + +Alternatively, the new migration command also supports stdin as input. This allows you to pipe in an existing script from another file or stdout. + +```bash +supabase migration new new_employee < create_employees_table.sql +``` + +Next, you want to apply the new migration to your local database. You can do so by running: + +```bash +supabase db reset +``` + +This command recreates your local database from scratch and applies all migration scripts under `supabase/migrations` directory. Now your local database is up to date. + +### Auto schema diff + +The key difference between manual migration is that auto schema diff creates a new migration script from changes **already** applied to your local database. + +![Auto schema diff](/img/guides/cli/diff-auto.png) + +The first step is to create an `employees` table under the `public` schema using Studio UI (accessible at [http://localhost:54323](http://localhost:54323/) by default). + +Next, generate a schema diff by running the following command: + +```bash +supabase db diff -f new_employee +``` + +You should see that a new file `supabase/migrations/_new_employee.sql` is created. Open the file and verify that the generated DDL statements are the same as below. + +```sql +-- This script was generated by the Schema Diff utility in pgAdmin 4 +-- For the circular dependencies, the order in which Schema Diff writes the objects is not very sophisticated +-- and may require manual changes to the script to ensure changes are applied in the correct order. +-- Please report an issue for any failure with the reproduction steps. + +CREATE TABLE IF NOT EXISTS public.employees +( + id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), + name text COLLATE pg_catalog."default", + CONSTRAINT employees_pkey PRIMARY KEY (id) +) + +TABLESPACE pg_default; + +ALTER TABLE IF EXISTS public.employees + OWNER to postgres; + +GRANT ALL ON TABLE public.employees TO anon; + +GRANT ALL ON TABLE public.employees TO authenticated; + +GRANT ALL ON TABLE public.employees TO postgres; + +GRANT ALL ON TABLE public.employees TO service_role; +``` + +You may notice that the auto generated migration script is more verbose than the manually written one. This is because the schema diff tool we use under the hood does not take into account of default privileges added by the initial schema. + +Alternatively, you may pass in the `--use-migra` experimental flag to generate a more concise schema diff. + +```sql +supabase db diff --use-migra +``` + +Without the `-f` file flag, the output will be written to stdout by default. + +Finally, commit the new migration script to git and you are ready to deploy 🎉 + +## Deploying a migration + +In a real project, you might not want to deploy migrations directly from your local machine as other engineers could be pushing features simultaneously. Instead, you would use a CI/CD pipeline to deploy new migrations. + +![Deploy migration](/img/guides/cli/deploy.png) + +In this section, we will show how to set up a CI/CD workflow with the CLI on GitHub Actions. We will use two projects here, one for production and one for staging. The prerequisites are: + +- Create separate Supabase projects for staging and production +- Push your Git repository to GitHub and enable GitHub Actions + +> ⚠️ You need a _new_ project for staging. A project which has already been modified to reflect the production project’s schema can’t be used because the CLI would reapply these changes. + +### Configure GitHub Actions + +The Supabase CLI requires a few environment variables to run in non-interactive mode. + +- `SUPABASE_ACCESS_TOKEN` is your personal access token +- `SUPABASE_DB_PASSWORD` is your project specific database password + +We recommend adding these as [encrypted secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) to your GitHub Action runners. + +Here are the workflow files we will be using for this guide: + +- `.github/workflows/ci.yml`: + +```yaml +name: CI + +on: + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: supabase/setup-cli@v1 + with: + version: 1.0.0 + + - name: Start Supabase local development setup + run: supabase start + + - name: Verify generated types are up-to-date + run: | + supabase gen types typescript --local > types.ts + if [ "$(git diff --ignore-space-at-eol types.ts | wc -l)" -gt "0" ]; then + echo "Detected uncommitted changes after build. See status below:" + git diff + exit 1 + fi +``` + +- `.github/workflows/production.yml`: + +```yaml +name: Deploy Migrations to Production + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-22.04 + + env: + SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} + SUPABASE_DB_PASSWORD: ${{ secrets.PRODUCTION_DB_PASSWORD }} + PRODUCTION_PROJECT_ID: abcdefghijklmnopqrst + + steps: + - uses: actions/checkout@v3 + + - uses: supabase/setup-cli@v1 + with: + version: 1.0.0 + + - run: | + supabase link --project-ref $PRODUCTION_PROJECT_ID + supabase db push +``` + +- `.github/workflows/staging.yml`: + +```yaml +name: Deploy Migrations to Staging + +on: + push: + branches: + - develop + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-22.04 + + env: + SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} + SUPABASE_DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }} + STAGING_PROJECT_ID: abcdefghijklmnopqrst + + steps: + - uses: actions/checkout@v3 + + - uses: supabase/setup-cli@v1 + with: + version: 1.0.0 + + - run: | + supabase link --project-ref $STAGING_PROJECT_ID + supabase db push +``` + +Commit these files to Git and push to your `main` branch on GitHub. Make sure you’ve updated these environment variables to match your Supabase projects: + +- `SUPABASE_ACCESS_TOKEN` +- `PRODUCTION_PROJECT_ID` +- `PRODUCTION_DB_PASSWORD` +- `STAGING_PROJECT_ID` +- `STAGING_DB_PASSWORD` + +When configured correctly, your repository should have CI and Release workflows that trigger on new commits pushed to `main` and `develop` branches. + +![Correctly configured repo](/img/guides/cli/ci-main.png) + +### Open a PR with new migration + +Now that your repository is set up, it’s time to create a new migration. Follow the [migration section](#creating-a-new-migration) to create a file `supabase/migrations/_new_employee.sql`. + +Checkout a new branch `feat/employee` from `develop` , commit the migration file, and push to GitHub. + +```bash +git checkout -b feat/employee +git add supabase/migrations/_new_employee.sql +git commit -m "Add employee table" +git push --set-upstream origin feat/employee +``` + +Then open a PR from `feat/employee` to `develop` branch. + +![Open new PR](/img/guides/cli/ci-pr.png) + +You can see that this triggers the test job on GitHub Actions. You can add more test steps to the job, such as running integration tests against the local database started by Supabase CLI. Here we assert that the generated types are up-to-date with new schema. + +![Test new PR](/img/guides/cli/ci-test.png) + +Once the test error are resolved, merge this PR, and watch the deployment in action 🚀 + +### Release to production + +After verifying your staging project has successfully migrated, create another PR from `develop` to `main` and merge it to deploy the migration to the production project. + +![Merge new PR](/img/guides/cli/ci-release.png) + +The `release` job applies all new migration scripts merged in `supabase/migrations` directory to a linked Supabase project. You can control which project the job links to via `PROJECT_ID` environment variable. + +The full example code for this guide is available on our [demo repository](https://github.com/supabase/supabase-action-example). + +## Troubleshooting + +### Sync production project to staging + +When setting up a new staging project, you might need to sync the initial schema with migrations previously applied to the production project. + +One way is to leverage the Release workflow: + +- Create a new branch `develop` and choose `main` as the branch source +- Push the `develop` branch to GitHub + +The GitHub Actions runner will deploy your existing migrations to the staging project. + +Alternatively, you can also apply migrations through your local CLI to a linked remote database. + +```sql +supabase db push +``` + +Once pushed, check that the migration version is up to date for both local and remote databases. + +```sql +supabase migration list +``` + +### Permission denied on db push + +If you created a table through Supabase dashboard, and your new migration script contains `ALTER TABLE` statements, you might run into permission error when applying them on staging or production databases. + +```bash +ERROR: must be owner of table employees (SQLSTATE 42501); while executing migration +``` + +This is because tables created through Supabase dashboard are owned by `supabase_admin` role while the migration scripts executed through CLI are under `postgres` role. + +One way to solve this is to grant `postgres` role additional privileges through the SQL Editor available on Supabase dashboard. For example, the following command grants postgres permissions to alter any table in the public schema. + +```sql +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO postgres; +``` + +### Rebasing new migrations + +Sometimes your teammate may merge a new migration file to git main branch, and now you need to rebase your local schema changes on top. + +![Rebase on main](/img/guides/cli/rebase.png) + +We can handle this scenario gracefully by renaming your old migration file with a new timestamp. + +```bash +git pull +supabase migration new dev_A +# Assume the new file is: supabase/migrations/_dev_A.sql +mv
`, - style: [` + style: [ + ` :host { display: block; margin: auto; @@ -612,20 +606,21 @@ import { Camera, CameraResultType } from '@capacitor/camera'; width: 100%; height: 100%; } - `], + `, + ], }) export class AvatarComponent implements OnInit { - _avatarUrl: SafeResourceUrl | undefined; - uploading = false; + _avatarUrl: SafeResourceUrl | undefined + uploading = false @Input() set avatarUrl(url: string | undefined) { if (url) { - this.downloadImage(url); + this.downloadImage(url) } } - @Output() upload = new EventEmitter(); + @Output() upload = new EventEmitter() constructor( private readonly supabase: SupabaseService, @@ -636,42 +631,46 @@ export class AvatarComponent implements OnInit { async downloadImage(path: string) { try { - const { data } = await this.supabase.downLoadImage(path); + const { data } = await this.supabase.downLoadImage(path) this._avatarUrl = this.dom.bypassSecurityTrustResourceUrl( URL.createObjectURL(data) - ); + ) } catch (error) { - console.error('Error downloading image: ', error.message); + console.error('Error downloading image: ', error.message) } } async uploadAvatar() { - const loader = await this.supabase.createLoader(); + const loader = await this.supabase.createLoader() try { const photo = await Camera.getPhoto({ resultType: CameraResultType.DataUrl, - }); + }) const file = await fetch(photo.dataUrl) .then((res) => res.blob()) - .then( (blob) => new File([blob], 'my-file', { type: `image/${photo.format}` })); + .then( + (blob) => + new File([blob], 'my-file', { type: `image/${photo.format}` }) + ) - const fileName = `${Math.random()}-${new Date().getTime()}.${ photo.format }`; + const fileName = `${Math.random()}-${new Date().getTime()}.${ + photo.format + }` - await loader.present(); - await this.supabase.uploadAvatar(fileName, file); + await loader.present() + await this.supabase.uploadAvatar(fileName, file) - this.upload.emit(fileName); + this.upload.emit(fileName) } catch (error) { - this.supabase.createNotice(error.message); + this.supabase.createNotice(error.message) } finally { - loader.dismiss(); + loader.dismiss() } } } ``` - ### Add the new widget And then we can add the widget on top of the **AccountComponent** html template: diff --git a/web/docs/guides/with-ionic-react.mdx b/apps/reference/docs/guides/with-ionic-react.mdx similarity index 89% rename from web/docs/guides/with-ionic-react.mdx rename to apps/reference/docs/guides/with-ionic-react.mdx index 4670c10f930..6885fd6fbac 100644 --- a/web/docs/guides/with-ionic-react.mdx +++ b/apps/reference/docs/guides/with-ionic-react.mdx @@ -1,11 +1,12 @@ --- id: with-ionic-react -title: "Quickstart: Ionic React" +title: 'Quickstart: Ionic React' description: Learn how to use Supabase in your Ionic React App. +sidebar_label: Ionic React --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Intro @@ -46,32 +47,34 @@ and then creating a "schema" inside the database. 1. Enter your project details. 1. Wait for the new database to launch. - ### Set up the database schema Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor, or you can just copy/paste the SQL from below and run it yourself. - + defaultValue="dashboard" + values={[ + {label: 'Dashboard', value: 'dashboard'}, + {label: 'SQL', value: 'sql'}, + ]}> + -```sh -1. Go to the "SQL Editor" section. -2. Click "User Management Starter". -3. Click "Run". -``` +1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard. +2. Click **User Management Starter**. +3. Click **Run**. - + ```sql -- Create a table for public "profiles" @@ -124,33 +127,24 @@ create policy "Anyone can upload an avatar." - ### Get the API Keys Now that you've created some database tables, you are ready to insert data using the auto-generated API. We just need to get the URL and `anon` key from the API settings. - - - -```sh -1. Go to the "Settings" section. -2. Click "API" in the sidebar. -3. Find your API URL in this page. -4. Find your "anon" and "service_role" keys on this page. -``` +1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard. +2. Click **API** in the sidebar. +3. Find your API `URL`, `anon`, and `service_role` keys on this page. - - - ## Building the App Let's start building the React app from scratch. @@ -430,30 +424,30 @@ export function AccountPage() { Now that we have all the components in place, let's update `App.tsx`: ```jsx title="src/App.tsx" -import { Redirect, Route } from 'react-router-dom'; -import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react'; -import { IonReactRouter } from '@ionic/react-router'; -import { supabase } from './supabaseClient'; +import { Redirect, Route } from 'react-router-dom' +import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react' +import { IonReactRouter } from '@ionic/react-router' +import { supabase } from './supabaseClient' -import '@ionic/react/css/ionic.bundle.css'; +import '@ionic/react/css/ionic.bundle.css' /* Theme variables */ -import './theme/variables.css'; -import { LoginPage } from './pages/Login'; -import { AccountPage } from './pages/Account'; -import { useEffect, useState } from 'react'; -import { Session } from '@supabase/supabase-js'; +import './theme/variables.css' +import { LoginPage } from './pages/Login' +import { AccountPage } from './pages/Account' +import { useEffect, useState } from 'react' +import { Session } from '@supabase/supabase-js' -setupIonicReact(); +setupIonicReact() const App: React.FC = () => { - const [session, setSession] = useState(null); + const [session, setSession] = (useState < Session) | (null > null) useEffect(() => { - setSession(supabase.auth.session()); + setSession(supabase.auth.session()) supabase.auth.onAuthStateChange((_event, session) => { - setSession(session); - }); - }, [session]); + setSession(session) + }) + }, [session]) return ( @@ -462,7 +456,7 @@ const App: React.FC = () => { exact path="/" render={() => { - return session ? : ; + return session ? : }} /> @@ -471,10 +465,10 @@ const App: React.FC = () => { - ); -}; + ) +} -export default App; +export default App ``` Once that's done, run this in a terminal window: @@ -506,24 +500,24 @@ Ionic PWA elements is a companion package that will polyfill certain browser API With those packages installed we can update our `index.tsx` to include an additional bootstapping call for the Ionic PWA Elements. ```ts title="src/index.tsx" -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; -import * as serviceWorkerRegistration from './serviceWorkerRegistration'; -import reportWebVitals from './reportWebVitals'; +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' +import * as serviceWorkerRegistration from './serviceWorkerRegistration' +import reportWebVitals from './reportWebVitals' -import {defineCustomElements} from '@ionic/pwa-elements/loader'; -defineCustomElements(window); +import { defineCustomElements } from '@ionic/pwa-elements/loader' +defineCustomElements(window) ReactDOM.render( , document.getElementById('root') -); +) -serviceWorkerRegistration.unregister(); -reportWebVitals(); +serviceWorkerRegistration.unregister() +reportWebVitals() ``` Then create an **AvatarComponent**. diff --git a/web/docs/guides/with-ionic-vue.mdx b/apps/reference/docs/guides/with-ionic-vue.mdx similarity index 56% rename from web/docs/guides/with-ionic-vue.mdx rename to apps/reference/docs/guides/with-ionic-vue.mdx index 98d53c804e2..ed4984c797e 100644 --- a/web/docs/guides/with-ionic-vue.mdx +++ b/apps/reference/docs/guides/with-ionic-vue.mdx @@ -1,11 +1,12 @@ --- id: with-ionic-vue -title: "Quickstart: Ionic Vue" +title: 'Quickstart: Ionic Vue' description: Learn how to use Supabase in your Ionic Vue App. +sidebar_label: Ionic Vue --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Intro @@ -46,32 +47,34 @@ and then creating a "schema" inside the database. 1. Enter your project details. 1. Wait for the new database to launch. - ### Set up the database schema Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor, or you can just copy/paste the SQL from below and run it yourself. - + defaultValue="dashboard" + values={[ + {label: 'Dashboard', value: 'dashboard'}, + {label: 'SQL', value: 'sql'}, + ]}> + -```sh -1. Go to the "SQL Editor" section. -2. Click "User Management Starter". -3. Click "Run". -``` +1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard. +2. Click **User Management Starter**. +3. Click **Run**. - + ```sql -- Create a table for public "profiles" @@ -124,33 +127,24 @@ create policy "Anyone can upload an avatar." - ### Get the API Keys Now that you've created some database tables, you are ready to insert data using the auto-generated API. We just need to get the URL and `anon` key from the API settings. - - - -```sh -1. Go to the "Settings" section. -2. Click "API" in the sidebar. -3. Find your API URL in this page. -4. Find your "anon" and "service_role" keys on this page. -``` +1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard. +2. Click **API** in the sidebar. +3. Find your API `URL`, `anon`, and `service_role` keys on this page. - - - ## Building the App Let's start building the Vue app from scratch. @@ -228,31 +222,12 @@ Let's set up a Vue component to manage logins and sign ups. We'll use Magic Link

{{email}}

- ``` @@ -351,118 +338,118 @@ Let's create a new component for that called `Account.vue`. ``` @@ -471,32 +458,31 @@ export default defineComponent({ Now that we have all the components in place, let's update `App.vue` and our routes: ```ts title="src/router.index.ts" -import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { RouteRecordRaw } from 'vue-router'; -import LoginPage from '../views/Login.vue'; -import AccountPage from '../views/Account.vue'; +import { createRouter, createWebHistory } from '@ionic/vue-router' +import { RouteRecordRaw } from 'vue-router' +import LoginPage from '../views/Login.vue' +import AccountPage from '../views/Account.vue' const routes: Array = [ { path: '/', name: 'Login', - component: LoginPage + component: LoginPage, }, { path: '/account', name: 'Account', - component: AccountPage - } + component: AccountPage, + }, ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), - routes + routes, }) export default router ``` - ```html title="src/App.vue" ``` @@ -562,24 +548,22 @@ With those packages installed we can update our `main.ts` to include an addition ```ts title="src/main.tsx" import { createApp } from 'vue' import App from './App.vue' -import router from './router'; +import router from './router' -import { IonicVue } from '@ionic/vue'; +import { IonicVue } from '@ionic/vue' /* Core CSS required for Ionic components to work properly */ -import '@ionic/vue/css/ionic.bundle.css'; +import '@ionic/vue/css/ionic.bundle.css' /* Theme variables */ -import './theme/variables.css'; +import './theme/variables.css' -import { defineCustomElements } from '@ionic/pwa-elements/loader'; -defineCustomElements(window); -const app = createApp(App) - .use(IonicVue) - .use(router); +import { defineCustomElements } from '@ionic/pwa-elements/loader' +defineCustomElements(window) +const app = createApp(App).use(IonicVue).use(router) router.isReady().then(() => { - app.mount('#app'); -}); + app.mount('#app') +}) ``` Then create an **AvatarComponent**. @@ -595,104 +579,105 @@ Then create an **AvatarComponent**. ``` ### Add the new widget And then we can add the widget to the Account page: + ```html title="src/views/Account.vue" - ``` - - ### Launch! Now that we have all the components in place, let's update `App.vue`: @@ -421,30 +411,29 @@ Now that we have all the components in place, let's update `App.vue`: - ``` Once that's done, run this in a terminal window: @@ -498,83 +487,81 @@ Let's create an avatar for the user so that they can upload a profile photo. We ``` - ### Add the new widget And then we can add the widget to the Account page: - ```html title="src/Profile.vue"