From f29223c4b4e8006f6a64769b7174ccbbab14bf25 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 21 Nov 2022 16:50:35 -0330 Subject: [PATCH 1/5] Fix custom heading links in mdx files --- .../CustomHTMLElements.utils.ts | 17 +++++------ .../docs/docs/reference/api/release-notes.mdx | 2 +- apps/docs/generator/templates/ApiTemplate.ts | 4 +-- .../generator/templates/ConfigTemplate.ts | 4 +-- apps/docs/pages/guides/api.mdx | 8 +++--- .../guides/auth/auth-helpers/auth-ui.mdx | 8 +++--- .../pages/guides/auth/auth-helpers/nextjs.mdx | 2 +- .../guides/auth/auth-helpers/sveltekit.mdx | 24 ++++++++-------- .../guides/database/extensions/pgnet.mdx | 6 ++-- .../guides/database/full-text-search.mdx | 10 +++---- .../pages/guides/migrations/firebase-auth.mdx | 10 +++---- .../guides/migrations/firebase-storage.mdx | 8 +++--- .../guides/migrations/firestore-data.mdx | 6 ++-- apps/docs/pages/guides/migrations/heroku.mdx | 8 +++--- .../pages/guides/platform/compute-add-ons.mdx | 28 +++++++++---------- apps/docs/pages/guides/with-nextjs.mdx | 14 ++++------ 16 files changed, 78 insertions(+), 81 deletions(-) diff --git a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts index e1bc479e468..ce33402dee9 100644 --- a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts +++ b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts @@ -1,11 +1,12 @@ // Check if heading has custom anchor first, before forming the anchor based on the title export const getAnchor = (text: any): string | undefined => { + console.log({ text }) if (typeof text === 'object') { + console.log('is object') if (Array.isArray(text)) { - const customAnchor = text.find( - (x) => typeof x === 'string' && x.includes('{#') && x.endsWith('}') - ) - if (customAnchor !== undefined) return customAnchor.slice(3, customAnchor.indexOf('}')) + console.log('is array') + const customAnchor = text.find((x) => typeof x === 'string' && x.startsWith('#')) + if (customAnchor !== undefined) return customAnchor.slice(1) const formattedText = text .map((x) => { @@ -33,8 +34,8 @@ export const getAnchor = (text: any): string | undefined => { return anchor } } else if (typeof text === 'string') { - if (text.includes('{#') && text.endsWith('}')) { - return text.slice(text.indexOf('{#') + 2, text.indexOf('}')) + if (text.startsWith('#')) { + return text.slice(1) } else { return text .toLowerCase() @@ -48,9 +49,9 @@ export const getAnchor = (text: any): string | undefined => { export const removeAnchor = (text: any) => { if (typeof text === 'object' && Array.isArray(text)) { - return text.filter((x) => !(typeof x === 'string' && x.includes('{#') && x.endsWith('}'))) + return text.filter((x) => !(typeof x === 'string' && x.startsWith('#'))) } else if (typeof text === 'string') { - if (text.indexOf('{#') > 0) return text.slice(0, text.indexOf('{#')) + if (text.startsWith('#')) return text.slice(1) else return text } return text diff --git a/apps/docs/docs/reference/api/release-notes.mdx b/apps/docs/docs/reference/api/release-notes.mdx index 266d24b2f35..f0d834e1605 100644 --- a/apps/docs/docs/reference/api/release-notes.mdx +++ b/apps/docs/docs/reference/api/release-notes.mdx @@ -3,7 +3,7 @@ id: release-notes title: Release Notes --- -## v1.0.0 {#1.0.0} +## v1.0.0 {`#1.0.0`} Adds the following routes: diff --git a/apps/docs/generator/templates/ApiTemplate.ts b/apps/docs/generator/templates/ApiTemplate.ts index e4b7c565e93..6e1d7a2ac84 100644 --- a/apps/docs/generator/templates/ApiTemplate.ts +++ b/apps/docs/generator/templates/ApiTemplate.ts @@ -16,7 +16,7 @@ toc_max_heading_level: 3 <% sections.forEach(function(section){ %> -## <%- section.title %> {#<%= section.id %>} +## <%- section.title %> {\`#<%= section.id %>\`} <%- section.description %> @@ -24,7 +24,7 @@ toc_max_heading_level: 3 -### <%- operation.summary %> {#<%- operation.operationId %>} +### <%- operation.summary %> {\`#<%- operation.operationId %>\`} \`\`\` <%- operation.operation.toUpperCase() %> <%- operation.fullPath %> diff --git a/apps/docs/generator/templates/ConfigTemplate.ts b/apps/docs/generator/templates/ConfigTemplate.ts index 5958218077f..2894991a012 100644 --- a/apps/docs/generator/templates/ConfigTemplate.ts +++ b/apps/docs/generator/templates/ConfigTemplate.ts @@ -14,11 +14,11 @@ toc_max_heading_level: 3 -## <%= section.title %> {#<%= section.id %>} +## <%= section.title %> {\`#<%= section.id %>\`} <% section.parameters.forEach(function(parameter){ %> -### \`<%- parameter.title %>\` {#<%= parameter.id %>} +### \`<%- parameter.title %>\` {\`#<%= parameter.id %>\`} <%- parameter.description %> diff --git a/apps/docs/pages/guides/api.mdx b/apps/docs/pages/guides/api.mdx index 07f55536c1a..481926a5a99 100644 --- a/apps/docs/pages/guides/api.mdx +++ b/apps/docs/pages/guides/api.mdx @@ -21,7 +21,7 @@ The APIs are: - **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 {`#rest-api-overview`} Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres. It provides everything you need from a CRUD API: @@ -41,7 +41,7 @@ It provides everything you need from a CRUD API: > -## GraphQL API {#graphql-api-overview} +## GraphQL API {`#graphql-api-overview`} @@ -51,7 +51,7 @@ GraphQL is in Beta, and may have breaking changes. It is only available on self- GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/pg-graphql), an open source PostgreSQL extension for GraphQL. -## Realtime API {#realtime-api-overview} +## Realtime API {`#realtime-api-overview`} Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets. Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications. @@ -130,7 +130,7 @@ You are provided with two keys: ### Accessing the docs in the Dashboard -#### REST API {#rest-api-dashboard-docs} +#### REST API {`#rest-api-dashboard-docs`} 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. diff --git a/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx index 2b4eff8c77a..82633a16b64 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx @@ -147,7 +147,7 @@ const App = () => ( If you created your own theme, you may not need to override any of the them. -### Create your own theme {#create-theme} +### 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). @@ -199,7 +199,7 @@ const App = () => ( You can swich between different variations of your theme with the ["theme" prop](#switch-theme-variations). -### Custom CSS classes {#custom-css-classes} +### Custom CSS classes {`#custom-css-classes`} You can use custom CSS classes for the following elements: `"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. @@ -224,7 +224,7 @@ const App = () => ( ) ``` -### Custom inline CSS {#custom-inline-styles} +### 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"`. @@ -249,7 +249,7 @@ const App = () => ( ) ``` -### Custom labels {#custom-labels} +### 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. diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index e6acf1da031..b130bcd4c2d 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -363,7 +363,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { -## Server-side data fetching to OAuth APIs using `provider token` {#oauth-provider-token} +## Server-side data fetching to OAuth APIs using `provider token` {`#oauth-provider-token`} When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. diff --git a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx index ed7fb35f055..95820b1644d 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx @@ -371,9 +371,9 @@ export const handle: Handle = async ({ event, resolve }) => { } ``` -## Migrate from 0.7.x to 0.8 {#migration} +## Migrate from 0.7.x to 0.8 {`#migration`} -### Set up the Supabase client {#migration-set-up-supabase-client} +### Set up the Supabase client {`#migration-set-up-supabase-client`} -### Initialize the client {#migration-initialize-client} +### Initialize the client {`#migration-initialize-client`} -### Set up hooks {#migration-set-up-hooks} +### Set up hooks {`#migration-set-up-hooks`} -### Typings {#migration-typings} +### Typings {`#migration-typings`} -### withPageAuth {#migration-with-page-auth} +### withPageAuth {`#migration-with-page-auth`} { -### withApiAuth {#migration-with-api-auth} +### withApiAuth {`#migration-with-api-auth`} { -## Migrate from 0.6.11 and below to 0.7.0 {#migration-0-7} +## Migrate from 0.6.11 and below to 0.7.0 {`#migration-0-7`} There are numerous breaking changes in the latest 0.7.0 version of this library. @@ -720,7 +720,7 @@ There are numerous breaking changes in the latest 0.7.0 version of this library. The environment variable prefix is now `PUBLIC_` instead of `VITE_` (e.g., `VITE_SUPABASE_URL` is now `PUBLIC_SUPABASE_URL`). -### Set up the Supabase client {#migration-set-up-supabase-client-0-7} +### Set up the Supabase client {`#migration-set-up-supabase-client-0-7`} -### Initialize the client {#migration-initialize-client-0-7} +### Initialize the client {`#migration-initialize-client-0-7`} -### Set up hooks {#migration-set-up-hooks-0-7} +### Set up hooks {`#migration-set-up-hooks-0-7`} -### Typings {#migration-typings-0-7} +### Typings {`#migration-typings-0-7`} -## `http_get` {#http_get} +## `http_get` {`#http_get`} Creates an HTTP GET request returning the request's ID. HTTP requests are not started until the transaction is committed. @@ -98,7 +98,7 @@ request_id After triggering `http_get`, use [`http_get_result`](#http_get_result) to get the result of the request. -## `http_post` {#http_post} +## `http_post` {`#http_post`} Creates an HTTP POST request with a JSON body, returning the request's ID. HTTP requests are not started until the transaction is committed. @@ -150,7 +150,7 @@ request_id After triggering `http_post`, use [`http_get_result`](#http_get_result) to get the result of the request. -## `http_collect_response` {#http_collect_response} +## `http_collect_response` {`#http_collect_response`} Given a `request_id` reference, retrieves the response. diff --git a/apps/docs/pages/guides/database/full-text-search.mdx b/apps/docs/pages/guides/database/full-text-search.mdx index bf25e78a453..075d34fc204 100644 --- a/apps/docs/pages/guides/database/full-text-search.mdx +++ b/apps/docs/pages/guides/database/full-text-search.mdx @@ -55,7 +55,7 @@ values The functions we'll cover in this guide are: -### `to_tsvector()` {#to-tsvector} +### `to_tsvector()` {`#to-tsvector`} Converts your data into searchable "tokens". `to_tsvector()` stands for "to text search vector". For example: @@ -67,14 +67,14 @@ select to_tsvector('green eggs and ham') Collectively these tokens are called a "document" which Postgres can use for comparisons. -### `to_tsquery()` {#to-tsquery} +### `to_tsquery()` {`#to-tsquery`} Converts a query string into "tokens" to match. `to_tsquery()` stands for "to text search query". This conversion step is important because we will want to "fuzzy match" on keywords. For example if a user searches for "eggs", and a column has the value "egg", we probably still want to return a match. -### Match: `@@` {#match} +### Match: `@@` {`#match`} The `@@` symbol is the "match" symbol for Full Text Search. It returns any matches between a `to_tsvector` result and a `to_tsquery` result. @@ -449,7 +449,7 @@ final result = await client Visit [PostgreSQL: Text Search Functions and Operators](https://www.postgresql.org/docs/current/functions-textsearch.html) to learn about additional query operators you can use to do more advanced `full text queries`, such as: -### Proximity: `<->` {#proximity} +### Proximity: `<->` {`#proximity`} The proximity symbol is useful for searching for terms that are a certain "distance" apart. For example, to find the phrase `big dreams`, where the a match for "big" is followed immediately by a match for "dreams": @@ -538,7 +538,7 @@ final result = await client -### Negation: `!` {#negation} +### Negation: `!` {`#negation`} The negation symbol can be used to find phrases which _don't_ contain a search term. For example, to find records that have the word `big` but not `little`: diff --git a/apps/docs/pages/guides/migrations/firebase-auth.mdx b/apps/docs/pages/guides/migrations/firebase-auth.mdx index a054f68de51..4093651ca85 100644 --- a/apps/docs/pages/guides/migrations/firebase-auth.mdx +++ b/apps/docs/pages/guides/migrations/firebase-auth.mdx @@ -12,7 +12,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase - `firestoreusers2json` ([TypeScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/firestoreusers2json.ts), [JavaScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/firestoreusers2json.js)) exports users from an existing Firebase project to a `.json` file on your local system. - `import_users` ([TypeScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/import_users.ts), [JavaScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/import_users.js)) imports users from a saved `.json` file into your Supabase project (inserting those users into the `auth.users` table of your `PostgreSQL` database instance). -## Set up the migration tool {#set-up-migration-tool} +## Set up the migration tool {`#set-up-migration-tool`} 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -36,7 +36,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Under **Connection Info**, copy the Host string and replace the entry in your `supabase-service.json` file. 1. Enter the password you used when you created your Supabase project in the `password` entry in the `supabase-service.json` file. -## Generate a Firebase private key {#generate-firebase-private-key} +## Generate a Firebase private key {`#generate-firebase-private-key`} 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -44,7 +44,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Click **Generate new private key**. 1. Rename the downloaded file to `firebase-service.json`. -## Save your Firebase password hash parameters {#save-firebase-hash-parameters} +## Save your Firebase password hash parameters {`#save-firebase-hash-parameters`} 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Select **Authentication** (Build section) in the sidebar. @@ -64,14 +64,14 @@ hash_config { ## Command line options -### Dump Firestore users to a JSON file {#dump-firestore-users} +### Dump Firestore users to a JSON file {`#dump-firestore-users`} `node firestoreusers2json.js [] []` - `filename.json`: (optional) output filename (defaults to `./users.json`) - `batchSize`: (optional) number of users to fetch in each batch (defaults to 100) -### Import JSON users file to Supabase Auth (PostgreSQL: auth.users) {#import-json-users-file} +### Import JSON users file to Supabase Auth (PostgreSQL: auth.users) {`#import-json-users-file`} `node import_users.js []` diff --git a/apps/docs/pages/guides/migrations/firebase-storage.mdx b/apps/docs/pages/guides/migrations/firebase-storage.mdx index df644481f42..c51fb1c4d75 100644 --- a/apps/docs/pages/guides/migrations/firebase-storage.mdx +++ b/apps/docs/pages/guides/migrations/firebase-storage.mdx @@ -12,7 +12,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase 1. Files are downloaded from a Firebase storage bucket to a local filesystem. 2. Files are uploaded from the local filesystem to a Supabase storage bucket. -## Set up the migration tool {#set-up-migration-tool} +## Set up the migration tool {`#set-up-migration-tool`} 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -25,7 +25,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Copy the **Project URL** and update the `SUPABASE_URL` value in `supabase-keys.js`. 1. Under **Project API keys**, copy the **service_role** key and update the `SUPABASE_KEY` value in `supabase-keys.js`. -## Generate a Firebase private key {#generate-firebase-private-key} +## Generate a Firebase private key {`#generate-firebase-private-key`} 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -35,7 +35,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git ## Command line options -### Download Firestore Storage bucket to a local filesystem folder {#download-firestore-storage-bucket} +### Download Firestore Storage bucket to a local filesystem folder {`#download-firestore-storage-bucket`} `node download.js [] [] [] []` @@ -47,7 +47,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git To process in batches using multiple command-line executions, you must use the same parameters with a new `` on subsequent calls. Use the token displayed on the last call to continue the process at a given point. -### Upload files to Supabase Storage bucket {#upload-to-supabase-storage-bucket} +### Upload files to Supabase Storage bucket {`#upload-to-supabase-storage-bucket`} `node upload.js ` diff --git a/apps/docs/pages/guides/migrations/firestore-data.mdx b/apps/docs/pages/guides/migrations/firestore-data.mdx index 936c8753758..72a64ae570b 100644 --- a/apps/docs/pages/guides/migrations/firestore-data.mdx +++ b/apps/docs/pages/guides/migrations/firestore-data.mdx @@ -11,7 +11,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase The Firestore `collection` is "flattened" and converted to a table with basic columns of one of the following types: `text`, `numeric`, `boolean`, or `jsonb`. If your structure is more complex, you can write a program to split the newly-created `json` file into multiple, related tables before you import your `json` file(s) to Supabase. -## Set up the migration tool {#set-up-migration-tool} +## Set up the migration tool {`#set-up-migration-tool`} 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -35,7 +35,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Under **Connection Info**, copy the Host string and replace the entry in your `supabase-service.json` file. 1. Enter the password you used when you created your Supabase project in the `password` entry in the `supabase-service.json` file. -## Generate a Firebase private key {#generate-firebase-private-key} +## Generate a Firebase private key {`#generate-firebase-private-key`} 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -79,7 +79,7 @@ And split it into two files (one table for users and one table for items): ] ``` -### Import JSON file to Supabase (PostgreSQL) {#import-to-supabase} +### Import JSON file to Supabase (PostgreSQL) {`#import-to-supabase`} `node json2supabase.js [] []` diff --git a/apps/docs/pages/guides/migrations/heroku.mdx b/apps/docs/pages/guides/migrations/heroku.mdx index 9ab54a1ce4a..8c95e05ebf8 100644 --- a/apps/docs/pages/guides/migrations/heroku.mdx +++ b/apps/docs/pages/guides/migrations/heroku.mdx @@ -22,7 +22,7 @@ Alternatively, use the [Heroku to Supabase migration tool](https://migrate.supab > -## Retrieve your Heroku database credentials {#retrieve-heroku-credentials} +## Retrieve your Heroku database credentials {`#retrieve-heroku-credentials`} 1. Log in to your [Heroku account](https://heroku.com) and select the project you want to migrate. 1. Click **Resources** in the menu and select your **Heroku Postgres** database. @@ -33,13 +33,13 @@ Alternatively, use the [Heroku to Supabase migration tool](https://migrate.supab - User (`$HEROKU_USER`) - Password (`$HEROKU_PASSWORD`) -## Retrieve your Supabase Host {#retrieve-supabase-host} +## Retrieve your Supabase Host {`#retrieve-supabase-host`} 1. If you're new to Supabase, [create a project](https://app.supabase.com). 1. Go to the [Database settings](https://app.supabase.com/project/_/settings/database) for your project in the Supabase Dashboard. 1. Under **Connection Info**, note your Host (`$SUPABASE_HOST`). -## Export your Heroku database to a file {#export-heroku-database} +## Export your Heroku database to a file {`#export-heroku-database`} Use `pg_dump` with your Heroku credentials to export your Heroku database to a file (e.g., `heroku_dump.sql`). @@ -49,7 +49,7 @@ pg_dump --clean --if-exists --quote-all-identifiers \ --no-owner --no-privileges > heroku_dump.sql ``` -## Import the database to your Supabase project {#import-database-to-supabase} +## Import the database to your Supabase project {`#import-database-to-supabase`} Use `psql` to import the Heroku database file to your Supabase project. diff --git a/apps/docs/pages/guides/platform/compute-add-ons.mdx b/apps/docs/pages/guides/platform/compute-add-ons.mdx index d175d4457c3..9403f03c06a 100644 --- a/apps/docs/pages/guides/platform/compute-add-ons.mdx +++ b/apps/docs/pages/guides/platform/compute-add-ons.mdx @@ -3,23 +3,23 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { id: 'compute-add-ons', title: 'Compute Add-ons', - description: 'Learn about your project\'s instance and additional add-ons.', + description: "Learn about your project's instance and additional add-ons.", } Every project on the Supabase Platform comes with its own dedicated Postgres instance running inside a virtual machine (VM). The following table describes the base instance with additional compute add-ons available if you need extra performance when scaling up Supabase. -Plan | Pricing | CPU | Memory | Disk IO Bandwidth | Connections: Direct | Connections: Pooler ------|---------|-----|--------|-------------------|---------------------|-------------------- -Free (Included) | $0 | 2-core ARM (shared) | 1 GB | Up to 2,085 Mbps | 10 (recommended) | 50 (recommended) -Small | $5 | 2-core ARM (shared) | 2 GB | Up to 2,085 Mbps | 30 (recommended) | 75 (recommended) -Medium | $50 | 2-core ARM (shared) | 4 GB | Up to 2,085 Mbps | 50 (recommended) | 150 (recommended) -Large | $100 | 2-core ARM (dedicated) | 8 GB | Up to 4,750 Mbps | 100 (recommended) | 300 (recommended) -XL | $200 | 4-core ARM (dedicated) | 16 GB | Up to 4,750 Mbps | 200 (recommended) | 600 (recommended) -2XL | $400 | 8-core ARM (dedicated) | 32 GB | Up to 4,750 Mbps | 350 (recommended) | 1200 (recommended) -4XL | $950 | 16-core ARM (dedicated) | 64 GB | Up to 4,750 Mbps | 420 (recommended) | 2800 (recommended) -8XL | $1,860 | 32-core ARM (dedicated) | 128 GB | Up to 9,000 Mbps | 450 (recommended) | 5600 (recommended) -12XL | $2,790 | 48-core ARM (dedicated) | 192 GB | Up to 13,500 Mbps | 480 (recommended) | 8600 (recommended) -16XL | $3,720 | 64-core ARM (dedicated) | 256 GB | Up to 19,000 Mbps | 500 (recommended) | 11,600 (recommended) +| Plan | Pricing | CPU | Memory | Disk IO Bandwidth | Connections: Direct | Connections: Pooler | +| --------------- | ------- | ----------------------- | ------ | ----------------- | ------------------- | -------------------- | +| Free (Included) | $0 | 2-core ARM (shared) | 1 GB | Up to 2,085 Mbps | 10 (recommended) | 50 (recommended) | +| Small | $5 | 2-core ARM (shared) | 2 GB | Up to 2,085 Mbps | 30 (recommended) | 75 (recommended) | +| Medium | $50 | 2-core ARM (shared) | 4 GB | Up to 2,085 Mbps | 50 (recommended) | 150 (recommended) | +| Large | $100 | 2-core ARM (dedicated) | 8 GB | Up to 4,750 Mbps | 100 (recommended) | 300 (recommended) | +| XL | $200 | 4-core ARM (dedicated) | 16 GB | Up to 4,750 Mbps | 200 (recommended) | 600 (recommended) | +| 2XL | $400 | 8-core ARM (dedicated) | 32 GB | Up to 4,750 Mbps | 350 (recommended) | 1200 (recommended) | +| 4XL | $950 | 16-core ARM (dedicated) | 64 GB | Up to 4,750 Mbps | 420 (recommended) | 2800 (recommended) | +| 8XL | $1,860 | 32-core ARM (dedicated) | 128 GB | Up to 9,000 Mbps | 450 (recommended) | 5600 (recommended) | +| 12XL | $2,790 | 48-core ARM (dedicated) | 192 GB | Up to 13,500 Mbps | 480 (recommended) | 8600 (recommended) | +| 16XL | $3,720 | 64-core ARM (dedicated) | 256 GB | Up to 19,000 Mbps | 500 (recommended) | 11,600 (recommended) | [Contact us](https://supabase.com/contact/enterprise) if you require a custom plan. @@ -27,7 +27,7 @@ XL | $200 | 4-core ARM (dedicated) | 16 GB | Up to 4,750 Mbps | 200 (recommended All Postgres instances on Supabase are dedicated applications running inside dedicated virtual machines. However, the underlying hardware resources, for example the physical CPU, may be shared between multiple VMs, but appear to the OS as if it is a dedicated hardware CPU. This is commonly referred to as a vCPU (virtual CPU). Cloud providers use these shared hardware resources to save cost—you can upgrade to a larger compute add-on to guarantee a dedicated physical CPU for your instance. -## Compute upgrades {#upgrades} +## Compute upgrades {`#upgrades`} When considering compute upgrades, assess whether your bottlenecks are hardware-constrained or software-constrained. For example, you may want to look into [optimizing the number of connections](/docs/guides/platform/performance#optimizing-the-number-of-connections) or [examining query performance](/docs/guides/platform/performance#examining-query-performance). When you're happy with your Postgres instance's performance, then you can focus on additional compute resources. For example, you can load test your application in staging to understand your compute requirements. You can also start out on a smaller tier, [create a report](https://app.supabase.com/project/_/reports) in the Dashboard to monitor your CPU utilization, and upgrade later as needed diff --git a/apps/docs/pages/guides/with-nextjs.mdx b/apps/docs/pages/guides/with-nextjs.mdx index 35883c7ffcf..e58126e0dd9 100644 --- a/apps/docs/pages/guides/with-nextjs.mdx +++ b/apps/docs/pages/guides/with-nextjs.mdx @@ -111,10 +111,7 @@ function MyApp({ Component, pageProps }) { const [supabase] = useState(() => createBrowserSupabaseClient()) return ( - + ) @@ -140,10 +137,7 @@ function MyApp({ const [supabase] = useState(() => createBrowserSupabaseClient()) return ( - + ) @@ -735,4 +729,6 @@ At this stage you have a fully functional application! export const Page = ({ children }) => -export default Page +export default Pag + +e From c98d3fd281e35ea4d90c1ab871b73eb373addafc Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 21 Nov 2022 22:58:40 -0330 Subject: [PATCH 2/5] Format anchor links --- .../CustomHTMLElements.utils.ts | 66 +- .../components/CustomHTMLElements/Heading.tsx | 1 - .../pages/guides/auth/auth-helpers/nextjs.mdx | 831 +----------------- 3 files changed, 37 insertions(+), 861 deletions(-) diff --git a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts index ce33402dee9..e6c06f3f12e 100644 --- a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts +++ b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts @@ -1,47 +1,35 @@ // Check if heading has custom anchor first, before forming the anchor based on the title export const getAnchor = (text: any): string | undefined => { - console.log({ text }) if (typeof text === 'object') { - console.log('is object') if (Array.isArray(text)) { - console.log('is array') - const customAnchor = text.find((x) => typeof x === 'string' && x.startsWith('#')) - if (customAnchor !== undefined) return customAnchor.slice(1) + const customAnchor = text + .find((x) => typeof x === 'object' && x.props.children.startsWith('#')) + .props.children.slice(1) - const formattedText = text - .map((x) => { - if (typeof x !== 'string') return x.props.children - else return x.trim() - }) - .map((x) => { - if (typeof x !== 'string') return x - else - return x - .toLowerCase() - .replace(/[^a-z0-9- ]/g, '') - .replace(/[ ]/g, '-') - }) - - return formattedText.join('-').toLowerCase() + return customAnchor + .toLowerCase() + .replace(/[^a-z0-9- ]/g, '') + .replace(/[ ]/g, '-') } else { const anchor = text.props.children + if (typeof anchor === 'string') { + console.log('anywhere') return anchor .toLowerCase() .replace(/[^a-z0-9- ]/g, '') .replace(/[ ]/g, '-') } + + if (anchor.endsWith('{')) return anchor.slice(0, -1) + return anchor } } else if (typeof text === 'string') { - if (text.startsWith('#')) { - return text.slice(1) - } else { - return text - .toLowerCase() - .replace(/[^a-z0-9- ]/g, '') - .replace(/[ ]/g, '-') - } + return text + .toLowerCase() + .replace(/[^a-z0-9- ]/g, '') + .replace(/[ ]/g, '-') } else { return undefined } @@ -49,9 +37,27 @@ export const getAnchor = (text: any): string | undefined => { export const removeAnchor = (text: any) => { if (typeof text === 'object' && Array.isArray(text)) { - return text.filter((x) => !(typeof x === 'string' && x.startsWith('#'))) + return text.filter((x) => { + console.log('its an object first') + if (x.props) { + if (!x.props.children.startsWith('#')) { + return x + } + } else { + console.log('so what is this then', x) + if (x.endsWith('}')) return + if (x.endsWith('{')) { + console.log('watttt', x) + return x.slice(0, -1).trim() + } else { + console.log('huhhhhhhhh', x) + return x + } + } + }) } else if (typeof text === 'string') { - if (text.startsWith('#')) return text.slice(1) + console.log('but then its a string') + if (text.endsWith('{')) return text.slice(0, -1) else return text } return text diff --git a/apps/docs/components/CustomHTMLElements/Heading.tsx b/apps/docs/components/CustomHTMLElements/Heading.tsx index 98703bbd944..b07ea6cab17 100644 --- a/apps/docs/components/CustomHTMLElements/Heading.tsx +++ b/apps/docs/components/CustomHTMLElements/Heading.tsx @@ -8,7 +8,6 @@ import { useInView } from 'react-intersection-observer' const Heading = ({ tag, children }) => { const HeadingTag = `${tag}` as any - const anchor = getAnchor(children) const link = `#${anchor}` diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index b130bcd4c2d..6ae7731c41b 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -7,836 +7,7 @@ export const meta = { sidebar_label: 'Next.js', } -This submodule provides convenience helpers for implementing user authentication in Next.js applications. - -## Install the Next.js helper library - - - - -```sh -npm install @supabase/auth-helpers-nextjs -``` - -This library supports the following tooling versions: - -- Node.js: `^10.13.0 || >=12.0.0` -- Next.js: `>=10` -- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). - -Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. - -```sh -npm install @supabase/auth-helpers-react -``` - - - - -```sh -yarn add @supabase/auth-helpers-nextjs -``` - -This library supports the following tooling versions: - -- Node.js: `^10.13.0 || >=12.0.0` -- Next.js: `>=10` -- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). - -Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. - -```sh -yarn add @supabase/auth-helpers-react -``` - - - - -## Set up environment variables - -Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. 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 title=.env.local -NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL -NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY -``` - -## Basic Setup - - - - -Wrap your `pages/_app.js` component with the `SessionContextProvider` component: - -```jsx title=pages/_app.js -import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { SessionContextProvider } from '@supabase/auth-helpers-react' - -function MyApp({ Component, pageProps }) { - const router = useRouter() - // Create a new supabase browser client on every first render. - const [supabaseClient] = useState(() => createBrowserSupabaseClient()) - - return ( - - - - ) -} -``` - - - - -Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component: - -```tsx lines=2,8 title=pages/_app.tsx -import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { SessionContextProvider, Session } from '@supabase/auth-helpers-react' - -function MyApp({ - Component, - pageProps, -}: AppProps<{ - initialSession: Session -}>) { - // Create a new supabase browser client on every first render. - const [supabaseClient] = useState(() => createBrowserSupabaseClient()) - - return ( - - - - ) -} -``` - - - - -You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined. - -## Usage with TypeScript - -You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: - -### Browser client - -Creating a new supabase client object: - -```tsx -import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { Database } from '../database.types' - -const supabaseClient = createBrowserSupabaseClient() -``` - -Retrieving a supabase client object from the SessionContext: - -```tsx -import { useSupabaseClient } from '@supabase/auth-helpers-react' -import { Database } from '../database.types' - -const supabaseClient = useSupabaseClient() -``` - -### Server client - -```tsx -// Creating a new supabase server client object (e.g. in API route): -import type { NextApiRequest, NextApiResponse } from 'next' -import type { Database } from 'types_db' - -export default async (req: NextApiRequest, res: NextApiResponse) => { - const supabaseServerClient = createServerSupabaseClient({ - req, - res, - }) - const { - data: { user }, - } = await supabaseServerClient.auth.getUser() - - res.status(200).json({ name: user?.name ?? '' }) -} -``` - -## Client-side data fetching with RLS - -For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to use the `supabaseClient` from the `useSupabaseClient` hook and only run your query once the user is defined client-side in the `useUser()` hook: - -```jsx lines=10-17 -import { Auth, ThemeSupa } from '@supabase/auth-ui-react' -import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react' -import { useEffect, useState } from 'react' - -const LoginPage = () => { - const supabaseClient = useSupabaseClient() - const user = 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 ( - - ) - - 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) - -Create a server supabase client to retrieve the logged in user's session: - -```jsx title=pages/profile.js -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -export default function Profile({ user }) { - return
Hello {user.name}
-} - -export const getServerSideProps = async (ctx) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - return { - props: { - initialSession: session, - user: session.user, - }, - } -} -``` - -## Server-side data fetching with RLS - -You can use the server supabase client to run [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) authenticated queries server-side: - - - - -```jsx -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -export default function ProtectedPage({ user, data }) { - return ( - <> -
Protected content for {user.email}
-
{JSON.stringify(data, null, 2)}
-
{JSON.stringify(user, null, 2)}
- - ) -} - -export const getServerSideProps = async (ctx) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - // Run queries with RLS on the server - const { data } = await supabase.from('users').select('*') - - return { - props: { - initialSession: session, - user: session.user, - data: data ?? [], - }, - } -} -``` - -
- - -```tsx -import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { GetServerSidePropsContext } from 'next' - -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 = async (ctx: GetServerSidePropsContext) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - // Run queries with RLS on the server - const { data } = await supabase.from('users').select('*') - - return { - props: { - initialSession: session, - user: session.user, - data: data ?? [], - }, - } -} -``` - -
-
- -## Server-side data fetching to OAuth APIs using `provider token` {`#oauth-provider-token`} - -When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. - - - - -```jsx -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -export default function ProtectedPage({ user, allRepos }) { - return ( - <> -
Protected content for {user.email}
-

Data fetched with provider token:

-
{JSON.stringify(allRepos, null, 2)}
-

user:

-
{JSON.stringify(user, null, 2)}
- - ) -} - -export const getServerSideProps = async (ctx) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - // Retrieve provider_token & logged in user's third-party id from metadata - const { provider_token, user } = session - const userId = user.user_metadata.user_name - - const allRepos = await ( - await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { - method: 'GET', - headers: { - Authorization: `token ${provider_token}`, - }, - }) - ).json() - - return { props: { user, allRepos } } -} -``` - -
- - -```tsx -import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { GetServerSidePropsContext } from 'next' - -export default function ProtectedPage({ user, allRepos }: { user: User; allRepos: any }) { - return ( - <> -
Protected content for {user.email}
-

Data fetched with provider token:

-
{JSON.stringify(allRepos, null, 2)}
-

user:

-
{JSON.stringify(user, null, 2)}
- - ) -} - -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - // Retrieve provider_token & logged in user's third-party id from metadata - const { provider_token, user } = session - const userId = user.user_metadata.user_name - - const allRepos = await ( - await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { - method: 'GET', - headers: { - Authorization: `token ${provider_token}`, - }, - }) - ).json() - - return { props: { user, allRepos } } -} -``` - -
-
- -## Protecting API routes - -Create a server supabase client to retrieve the logged in user's session: - - - - -```jsx title=pages/api/protected-route.js -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -const ProtectedRoute = async (req, res) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient({ req, res }) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return res.status(401).json({ - error: 'not_authenticated', - description: 'The user does not have an active session or is not authenticated', - }) - - // Run queries with RLS on the server - const { data } = await supabase.from('test').select('*') - res.json(data) -} - -export default ProtectedRoute -``` - - - - -```tsx title=pages/api/protected-route.ts -import { NextApiHandler } from 'next' -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -const ProtectedRoute: NextApiHandler = async (req, res) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient({ req, res }) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return res.status(401).json({ - error: 'not_authenticated', - description: 'The user does not have an active session or is not authenticated', - }) - - // Run queries with RLS on the server - const { data } = await supabase.from('test').select('*') - res.json(data) -} - -export default ProtectedRoute -``` - - - - -## Auth with Next.js Middleware - -As an alternative to protecting individual pages you can use a [Next.js Middleware](https://nextjs.org/docs/middleware) to protect the entire directory or those that match the config object. In the following example, all requests to `/middleware-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: - -```ts title=middleware.ts -import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { NextResponse } from 'next/server' -import type { NextRequest } from 'next/server' - -export async function middleware(req: NextRequest) { - // We need to create a response and hand it to the supabase client to be able to modify the response headers. - const res = NextResponse.next() - // Create authenticated Supabase Client. - const supabase = createMiddlewareSupabaseClient({ req, res }) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - // Check auth condition - if (session?.user.email?.endsWith('@gmail.com')) { - // Authentication successful, forward request to protected route. - return res - } - - // Auth condition not met, redirect to home page. - const redirectUrl = req.nextUrl.clone() - redirectUrl.pathname = '/' - redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) - return NextResponse.redirect(redirectUrl) -} - -export const config = { - matcher: '/middleware-protected', -} -``` - -## Migration Guide - -### Migrating to v0.5.X - -To make these helpers more flexible as well as more maintainable and easier to upgrade for new versions of Next.js, we're stripping them down to the most useful part which is managing the cookies and giving you an authenticated supabase-js client in any environment (client, server, middleware/edge). - -Therefore we're marking the `withApiAuth`, `withPageAuth`, and `withMiddlewareAuth` higher order functions as deprectaed and they will be removed in the next **minor** release (v0.6.X). - -Please follow the steps below to update your API routes, pages, and middleware handlers. Thanks! - -#### `withApiAuth` deprecated! - -Use `createServerSupabaseClient` within your `NextApiHandler`: - - - - -```tsx title=pages/api/protected-route.ts -import { withApiAuth } from '@supabase/auth-helpers-nextjs' - -export default withApiAuth(async function ProtectedRoute(req, res, supabase) { - // Run queries with RLS on the server - const { data } = await supabase.from('test').select('*') - res.json(data) -}) -``` - - - - -```tsx title=pages/api/protected-route.ts -import { NextApiHandler } from 'next' -import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' - -const ProtectedRoute: NextApiHandler = async (req, res) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient({ req, res }) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return res.status(401).json({ - error: 'not_authenticated', - description: 'The user does not have an active session or is not authenticated', - }) - - // Run queries with RLS on the server - const { data } = await supabase.from('test').select('*') - res.json(data) -} - -export default ProtectedRoute -``` - - - - -#### `withPageAuth` deprecated! - -Use `createServerSupabaseClient` within `getServerSideProps`: - - - - -```tsx title=pages/profile.tsx -import { withPageAuth, User } from '@supabase/auth-helpers-nextjs' - -export default function Profile({ user }: { user: User }) { - return
{JSON.stringify(user, null, 2)}
-} - -export const getServerSideProps = withPageAuth({ redirectTo: '/' }) -``` - -
- - -```tsx title=pages/profile.js -import { createServerSupabaseClient, User } from '@supabase/auth-helpers-nextjs' -import { GetServerSidePropsContext } from 'next' - -export default function Profile({ user }: { user: User }) { - return
{JSON.stringify(user, null, 2)}
-} - -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - // Create authenticated Supabase Client - const supabase = createServerSupabaseClient(ctx) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) - return { - redirect: { - destination: '/', - permanent: false, - }, - } - - return { - props: { - initialSession: session, - user: session.user, - }, - } -} -``` - -
-
- -#### `withMiddlewareAuth` deprecated! - - - - -```tsx title=middleware.ts -import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs' - -export const middleware = withMiddlewareAuth({ - redirectTo: '/', - authGuard: { - isPermitted: async (user) => { - return user.email?.endsWith('@gmail.com') ?? false - }, - redirectTo: '/insufficient-permissions', - }, -}) - -export const config = { - matcher: '/middleware-protected', -} -``` - - - - -```tsx title=middleware.ts -import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { NextResponse } from 'next/server' -import type { NextRequest } from 'next/server' - -export async function middleware(req: NextRequest) { - // We need to create a response and hand it to the supabase client to be able to modify the response headers. - const res = NextResponse.next() - // Create authenticated Supabase Client. - const supabase = createMiddlewareSupabaseClient({ req, res }) - // Check if we have a session - const { - data: { session }, - } = await supabase.auth.getSession() - - // Check auth condition - if (session?.user.email?.endsWith('@gmail.com')) { - // Authentication successful, forward request to protected route. - return res - } - - // Auth condition not met, redirect to home page. - const redirectUrl = req.nextUrl.clone() - redirectUrl.pathname = '/' - redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) - return NextResponse.redirect(redirectUrl) -} - -export const config = { - matcher: '/middleware-protected', -} -``` - - - - -### Migrating to v0.4.X and supabase-js v2 - -With the update to `supabase-js` v2 the `auth` API routes are no longer required, therefore you can go ahead and delete your `auth` directory under the `/pages/api/` directory. Please refer to the [v2 migration guide](/docs/reference/javascript/upgrade-guide) for the full set of changes within supabase-js. - -The `/api/auth/logout` API route has been removed, please use the `signout` method instead: - -```jsx - -``` - -The `supabaseClient` and `supabaseServerClient` have been removed in favor of the `createBrowserSupabaseClient` and `createServerSupabaseClient` methods. This allows you to provide the CLI-generated types to the client: - -```tsx -// client-side -import type { Database } from 'types_db' -const [supabaseClient] = useState(() => createBrowserSupabaseClient()) - -// server-side API route -import type { NextApiRequest, NextApiResponse } from 'next' -import type { Database } from 'types_db' - -export default async (req: NextApiRequest, res: NextApiResponse) => { - const supabaseServerClient = createServerSupabaseClient({ - req, - res, - }) - const { - data: { user }, - } = await supabaseServerClient.auth.getUser() - - res.status(200).json({ name: user?.name ?? '' }) -} -``` - -- The `UserProvider` has been replaced by the `SessionContextProvider`. Make sure to wrap your `pages/_app.js` componenent with the `SessionContextProvider`. Then, throughout your application you can use the `useSessionContext` hook to get the `session` and the `useSupabaseClient` hook to get an authenticated `supabaseClient`. -- The `useUser` hook now returns the `user` object or `null`. -- Usage with TypeScript: You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: - -Creating a new supabase client object: - -```tsx -import { Database } from '../database.types' - -const [supabaseClient] = useState(() => createBrowserSupabaseClient()) -``` - -Retrieving a supabase client object from the SessionContext: - -```tsx -import { useSupabaseClient } from '@supabase/auth-helpers-react' -import { Database } from '../database.types' - -const supabaseClient = useSupabaseClient() -``` +## With just text {`#with-just-text`} export const Page = ({ children }) => From c7ea137be3ec2b05d7cba91409414474d08e6256 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 21 Nov 2022 23:08:16 -0330 Subject: [PATCH 3/5] Restore nextjs file --- .../pages/guides/auth/auth-helpers/nextjs.mdx | 831 +++++++++++++++++- 1 file changed, 830 insertions(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index 6ae7731c41b..e6acf1da031 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -7,7 +7,836 @@ export const meta = { sidebar_label: 'Next.js', } -## With just text {`#with-just-text`} +This submodule provides convenience helpers for implementing user authentication in Next.js applications. + +## Install the Next.js helper library + + + + +```sh +npm install @supabase/auth-helpers-nextjs +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` +- Next.js: `>=10` +- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). + +Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. + +```sh +npm install @supabase/auth-helpers-react +``` + + + + +```sh +yarn add @supabase/auth-helpers-nextjs +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` +- Next.js: `>=10` +- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). + +Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. + +```sh +yarn add @supabase/auth-helpers-react +``` + + + + +## Set up environment variables + +Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. 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 title=.env.local +NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL +NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY +``` + +## Basic Setup + + + + +Wrap your `pages/_app.js` component with the `SessionContextProvider` component: + +```jsx title=pages/_app.js +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { SessionContextProvider } from '@supabase/auth-helpers-react' + +function MyApp({ Component, pageProps }) { + const router = useRouter() + // Create a new supabase browser client on every first render. + const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + + return ( + + + + ) +} +``` + + + + +Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component: + +```tsx lines=2,8 title=pages/_app.tsx +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { SessionContextProvider, Session } from '@supabase/auth-helpers-react' + +function MyApp({ + Component, + pageProps, +}: AppProps<{ + initialSession: Session +}>) { + // Create a new supabase browser client on every first render. + const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + + return ( + + + + ) +} +``` + + + + +You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined. + +## Usage with TypeScript + +You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: + +### Browser client + +Creating a new supabase client object: + +```tsx +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { Database } from '../database.types' + +const supabaseClient = createBrowserSupabaseClient() +``` + +Retrieving a supabase client object from the SessionContext: + +```tsx +import { useSupabaseClient } from '@supabase/auth-helpers-react' +import { Database } from '../database.types' + +const supabaseClient = useSupabaseClient() +``` + +### Server client + +```tsx +// Creating a new supabase server client object (e.g. in API route): +import type { NextApiRequest, NextApiResponse } from 'next' +import type { Database } from 'types_db' + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const supabaseServerClient = createServerSupabaseClient({ + req, + res, + }) + const { + data: { user }, + } = await supabaseServerClient.auth.getUser() + + res.status(200).json({ name: user?.name ?? '' }) +} +``` + +## Client-side data fetching with RLS + +For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to use the `supabaseClient` from the `useSupabaseClient` hook and only run your query once the user is defined client-side in the `useUser()` hook: + +```jsx lines=10-17 +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' +import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react' +import { useEffect, useState } from 'react' + +const LoginPage = () => { + const supabaseClient = useSupabaseClient() + const user = 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 ( + + ) + + 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) + +Create a server supabase client to retrieve the logged in user's session: + +```jsx title=pages/profile.js +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }) { + return
Hello {user.name}
+} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + return { + props: { + initialSession: session, + user: session.user, + }, + } +} +``` + +## Server-side data fetching with RLS + +You can use the server supabase client to run [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) authenticated queries server-side: + + + + +```jsx +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, data }) { + return ( + <> +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Run queries with RLS on the server + const { data } = await supabase.from('users').select('*') + + return { + props: { + initialSession: session, + user: session.user, + data: data ?? [], + }, + } +} +``` + +
+ + +```tsx +import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +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 = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Run queries with RLS on the server + const { data } = await supabase.from('users').select('*') + + return { + props: { + initialSession: session, + user: session.user, + data: data ?? [], + }, + } +} +``` + +
+
+ +## Server-side data fetching to OAuth APIs using `provider token` {#oauth-provider-token} + +When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. + + + + +```jsx +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, allRepos }) { + return ( + <> +
Protected content for {user.email}
+

Data fetched with provider token:

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

user:

+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Retrieve provider_token & logged in user's third-party id from metadata + const { provider_token, user } = session + const userId = user.user_metadata.user_name + + const allRepos = await ( + await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { + method: 'GET', + headers: { + Authorization: `token ${provider_token}`, + }, + }) + ).json() + + return { props: { user, allRepos } } +} +``` + +
+ + +```tsx +import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +export default function ProtectedPage({ user, allRepos }: { user: User; allRepos: any }) { + return ( + <> +
Protected content for {user.email}
+

Data fetched with provider token:

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

user:

+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Retrieve provider_token & logged in user's third-party id from metadata + const { provider_token, user } = session + const userId = user.user_metadata.user_name + + const allRepos = await ( + await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { + method: 'GET', + headers: { + Authorization: `token ${provider_token}`, + }, + }) + ).json() + + return { props: { user, allRepos } } +} +``` + +
+
+ +## Protecting API routes + +Create a server supabase client to retrieve the logged in user's session: + + + + +```jsx title=pages/api/protected-route.js +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +```tsx title=pages/api/protected-route.ts +import { NextApiHandler } from 'next' +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute: NextApiHandler = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +## Auth with Next.js Middleware + +As an alternative to protecting individual pages you can use a [Next.js Middleware](https://nextjs.org/docs/middleware) to protect the entire directory or those that match the config object. In the following example, all requests to `/middleware-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: + +```ts title=middleware.ts +import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export async function middleware(req: NextRequest) { + // We need to create a response and hand it to the supabase client to be able to modify the response headers. + const res = NextResponse.next() + // Create authenticated Supabase Client. + const supabase = createMiddlewareSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + // Check auth condition + if (session?.user.email?.endsWith('@gmail.com')) { + // Authentication successful, forward request to protected route. + return res + } + + // Auth condition not met, redirect to home page. + const redirectUrl = req.nextUrl.clone() + redirectUrl.pathname = '/' + redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) + return NextResponse.redirect(redirectUrl) +} + +export const config = { + matcher: '/middleware-protected', +} +``` + +## Migration Guide + +### Migrating to v0.5.X + +To make these helpers more flexible as well as more maintainable and easier to upgrade for new versions of Next.js, we're stripping them down to the most useful part which is managing the cookies and giving you an authenticated supabase-js client in any environment (client, server, middleware/edge). + +Therefore we're marking the `withApiAuth`, `withPageAuth`, and `withMiddlewareAuth` higher order functions as deprectaed and they will be removed in the next **minor** release (v0.6.X). + +Please follow the steps below to update your API routes, pages, and middleware handlers. Thanks! + +#### `withApiAuth` deprecated! + +Use `createServerSupabaseClient` within your `NextApiHandler`: + + + + +```tsx title=pages/api/protected-route.ts +import { withApiAuth } from '@supabase/auth-helpers-nextjs' + +export default withApiAuth(async function ProtectedRoute(req, res, supabase) { + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +}) +``` + + + + +```tsx title=pages/api/protected-route.ts +import { NextApiHandler } from 'next' +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute: NextApiHandler = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +#### `withPageAuth` deprecated! + +Use `createServerSupabaseClient` within `getServerSideProps`: + + + + +```tsx title=pages/profile.tsx +import { withPageAuth, User } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }: { user: User }) { + return
{JSON.stringify(user, null, 2)}
+} + +export const getServerSideProps = withPageAuth({ redirectTo: '/' }) +``` + +
+ + +```tsx title=pages/profile.js +import { createServerSupabaseClient, User } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +export default function Profile({ user }: { user: User }) { + return
{JSON.stringify(user, null, 2)}
+} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + return { + props: { + initialSession: session, + user: session.user, + }, + } +} +``` + +
+
+ +#### `withMiddlewareAuth` deprecated! + + + + +```tsx title=middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs' + +export const middleware = withMiddlewareAuth({ + redirectTo: '/', + authGuard: { + isPermitted: async (user) => { + return user.email?.endsWith('@gmail.com') ?? false + }, + redirectTo: '/insufficient-permissions', + }, +}) + +export const config = { + matcher: '/middleware-protected', +} +``` + + + + +```tsx title=middleware.ts +import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export async function middleware(req: NextRequest) { + // We need to create a response and hand it to the supabase client to be able to modify the response headers. + const res = NextResponse.next() + // Create authenticated Supabase Client. + const supabase = createMiddlewareSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + // Check auth condition + if (session?.user.email?.endsWith('@gmail.com')) { + // Authentication successful, forward request to protected route. + return res + } + + // Auth condition not met, redirect to home page. + const redirectUrl = req.nextUrl.clone() + redirectUrl.pathname = '/' + redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) + return NextResponse.redirect(redirectUrl) +} + +export const config = { + matcher: '/middleware-protected', +} +``` + + + + +### Migrating to v0.4.X and supabase-js v2 + +With the update to `supabase-js` v2 the `auth` API routes are no longer required, therefore you can go ahead and delete your `auth` directory under the `/pages/api/` directory. Please refer to the [v2 migration guide](/docs/reference/javascript/upgrade-guide) for the full set of changes within supabase-js. + +The `/api/auth/logout` API route has been removed, please use the `signout` method instead: + +```jsx + +``` + +The `supabaseClient` and `supabaseServerClient` have been removed in favor of the `createBrowserSupabaseClient` and `createServerSupabaseClient` methods. This allows you to provide the CLI-generated types to the client: + +```tsx +// client-side +import type { Database } from 'types_db' +const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + +// server-side API route +import type { NextApiRequest, NextApiResponse } from 'next' +import type { Database } from 'types_db' + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const supabaseServerClient = createServerSupabaseClient({ + req, + res, + }) + const { + data: { user }, + } = await supabaseServerClient.auth.getUser() + + res.status(200).json({ name: user?.name ?? '' }) +} +``` + +- The `UserProvider` has been replaced by the `SessionContextProvider`. Make sure to wrap your `pages/_app.js` componenent with the `SessionContextProvider`. Then, throughout your application you can use the `useSessionContext` hook to get the `session` and the `useSupabaseClient` hook to get an authenticated `supabaseClient`. +- The `useUser` hook now returns the `user` object or `null`. +- Usage with TypeScript: You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: + +Creating a new supabase client object: + +```tsx +import { Database } from '../database.types' + +const [supabaseClient] = useState(() => createBrowserSupabaseClient()) +``` + +Retrieving a supabase client object from the SessionContext: + +```tsx +import { useSupabaseClient } from '@supabase/auth-helpers-react' +import { Database } from '../database.types' + +const supabaseClient = useSupabaseClient() +``` export const Page = ({ children }) => From 927e624ef6187abc591e9d6c579ee8ed6accd162 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Tue, 22 Nov 2022 09:52:50 -0330 Subject: [PATCH 4/5] Change the format of anchor links --- .../CustomHTMLElements.utils.ts | 65 +++++++++---------- .../docs/docs/reference/api/release-notes.mdx | 2 +- apps/docs/generator/templates/ApiTemplate.ts | 4 +- .../generator/templates/ConfigTemplate.ts | 4 +- apps/docs/pages/guides/api.mdx | 8 +-- .../guides/auth/auth-helpers/auth-ui.mdx | 8 +-- .../guides/auth/auth-helpers/sveltekit.mdx | 24 +++---- .../guides/database/extensions/pgnet.mdx | 6 +- .../guides/database/full-text-search.mdx | 10 +-- .../pages/guides/migrations/firebase-auth.mdx | 10 +-- .../guides/migrations/firebase-storage.mdx | 8 +-- .../guides/migrations/firestore-data.mdx | 6 +- apps/docs/pages/guides/migrations/heroku.mdx | 8 +-- .../pages/guides/platform/compute-add-ons.mdx | 2 +- 14 files changed, 79 insertions(+), 86 deletions(-) diff --git a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts index e6c06f3f12e..305ac4fa170 100644 --- a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts +++ b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts @@ -2,34 +2,45 @@ export const getAnchor = (text: any): string | undefined => { if (typeof text === 'object') { if (Array.isArray(text)) { - const customAnchor = text - .find((x) => typeof x === 'object' && x.props.children.startsWith('#')) - .props.children.slice(1) + const customAnchor = text.find( + (x) => typeof x === 'string' && x.includes('[#') && x.endsWith(']') + ) + if (customAnchor !== undefined) return customAnchor.slice(2, customAnchor.indexOf(']')) - return customAnchor - .toLowerCase() - .replace(/[^a-z0-9- ]/g, '') - .replace(/[ ]/g, '-') + const formattedText = text + .map((x) => { + if (typeof x !== 'string') return x.props.children + else return x.trim() + }) + .map((x) => { + if (typeof x !== 'string') return x + else + return x + .toLowerCase() + .replace(/[^a-z0-9- ]/g, '') + .replace(/[ ]/g, '-') + }) + + return formattedText.join('-').toLowerCase() } else { const anchor = text.props.children - if (typeof anchor === 'string') { - console.log('anywhere') return anchor .toLowerCase() .replace(/[^a-z0-9- ]/g, '') .replace(/[ ]/g, '-') } - - if (anchor.endsWith('{')) return anchor.slice(0, -1) - return anchor } } else if (typeof text === 'string') { - return text - .toLowerCase() - .replace(/[^a-z0-9- ]/g, '') - .replace(/[ ]/g, '-') + if (text.includes('[#') && text.endsWith(']')) { + return text.slice(text.indexOf('[#') + 2, text.indexOf(']')) + } else { + return text + .toLowerCase() + .replace(/[^a-z0-9- ]/g, '') + .replace(/[ ]/g, '-') + } } else { return undefined } @@ -37,27 +48,9 @@ export const getAnchor = (text: any): string | undefined => { export const removeAnchor = (text: any) => { if (typeof text === 'object' && Array.isArray(text)) { - return text.filter((x) => { - console.log('its an object first') - if (x.props) { - if (!x.props.children.startsWith('#')) { - return x - } - } else { - console.log('so what is this then', x) - if (x.endsWith('}')) return - if (x.endsWith('{')) { - console.log('watttt', x) - return x.slice(0, -1).trim() - } else { - console.log('huhhhhhhhh', x) - return x - } - } - }) + return text.filter((x) => !(typeof x === 'string' && x.includes('[#') && x.endsWith(']'))) } else if (typeof text === 'string') { - console.log('but then its a string') - if (text.endsWith('{')) return text.slice(0, -1) + if (text.indexOf('[#') > 0) return text.slice(0, text.indexOf('[#')) else return text } return text diff --git a/apps/docs/docs/reference/api/release-notes.mdx b/apps/docs/docs/reference/api/release-notes.mdx index f0d834e1605..9cc40bf694e 100644 --- a/apps/docs/docs/reference/api/release-notes.mdx +++ b/apps/docs/docs/reference/api/release-notes.mdx @@ -3,7 +3,7 @@ id: release-notes title: Release Notes --- -## v1.0.0 {`#1.0.0`} +## v1.0.0 [#1.0.0] Adds the following routes: diff --git a/apps/docs/generator/templates/ApiTemplate.ts b/apps/docs/generator/templates/ApiTemplate.ts index 6e1d7a2ac84..bf95eef4f0c 100644 --- a/apps/docs/generator/templates/ApiTemplate.ts +++ b/apps/docs/generator/templates/ApiTemplate.ts @@ -16,7 +16,7 @@ toc_max_heading_level: 3 <% sections.forEach(function(section){ %> -## <%- section.title %> {\`#<%= section.id %>\`} +## <%- section.title %> [#<%= section.id %>] <%- section.description %> @@ -24,7 +24,7 @@ toc_max_heading_level: 3 -### <%- operation.summary %> {\`#<%- operation.operationId %>\`} +### <%- operation.summary %> [#<%- operation.operationId %>] \`\`\` <%- operation.operation.toUpperCase() %> <%- operation.fullPath %> diff --git a/apps/docs/generator/templates/ConfigTemplate.ts b/apps/docs/generator/templates/ConfigTemplate.ts index 2894991a012..3300e030de8 100644 --- a/apps/docs/generator/templates/ConfigTemplate.ts +++ b/apps/docs/generator/templates/ConfigTemplate.ts @@ -14,11 +14,11 @@ toc_max_heading_level: 3 -## <%= section.title %> {\`#<%= section.id %>\`} +## <%= section.title %> [#<%= section.id %>] <% section.parameters.forEach(function(parameter){ %> -### \`<%- parameter.title %>\` {\`#<%= parameter.id %>\`} +### \`<%- parameter.title %>\` [#<%= parameter.id %>] <%- parameter.description %> diff --git a/apps/docs/pages/guides/api.mdx b/apps/docs/pages/guides/api.mdx index 481926a5a99..ac135dbc7b4 100644 --- a/apps/docs/pages/guides/api.mdx +++ b/apps/docs/pages/guides/api.mdx @@ -21,7 +21,7 @@ The APIs are: - **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 [#rest-api-overview] Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres. It provides everything you need from a CRUD API: @@ -41,7 +41,7 @@ It provides everything you need from a CRUD API: > -## GraphQL API {`#graphql-api-overview`} +## GraphQL API [#graphql-api-overview] @@ -51,7 +51,7 @@ GraphQL is in Beta, and may have breaking changes. It is only available on self- GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/pg-graphql), an open source PostgreSQL extension for GraphQL. -## Realtime API {`#realtime-api-overview`} +## Realtime API [#realtime-api-overview] Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets. Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications. @@ -130,7 +130,7 @@ You are provided with two keys: ### Accessing the docs in the Dashboard -#### REST API {`#rest-api-dashboard-docs`} +#### REST API [#rest-api-dashboard-docs] 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. diff --git a/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx index 82633a16b64..2a7814999e3 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx @@ -147,7 +147,7 @@ const App = () => ( If you created your own theme, you may not need to override any of the them. -### Create your own theme {`#create-theme`} +### 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). @@ -199,7 +199,7 @@ const App = () => ( You can swich between different variations of your theme with the ["theme" prop](#switch-theme-variations). -### Custom CSS classes {`#custom-css-classes`} +### Custom CSS classes [#custom-css-classes] You can use custom CSS classes for the following elements: `"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. @@ -224,7 +224,7 @@ const App = () => ( ) ``` -### Custom inline CSS {`#custom-inline-styles`} +### 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"`. @@ -249,7 +249,7 @@ const App = () => ( ) ``` -### Custom labels {`#custom-labels`} +### 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. diff --git a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx index 95820b1644d..62e6a0154e0 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx @@ -371,9 +371,9 @@ export const handle: Handle = async ({ event, resolve }) => { } ``` -## Migrate from 0.7.x to 0.8 {`#migration`} +## Migrate from 0.7.x to 0.8 [#migration] -### Set up the Supabase client {`#migration-set-up-supabase-client`} +### Set up the Supabase client [#migration-set-up-supabase-client] -### Initialize the client {`#migration-initialize-client`} +### Initialize the client [#migration-initialize-client] -### Set up hooks {`#migration-set-up-hooks`} +### Set up hooks [#migration-set-up-hooks] -### Typings {`#migration-typings`} +### Typings [#migration-typings] -### withPageAuth {`#migration-with-page-auth`} +### withPageAuth [#migration-with-page-auth] { -### withApiAuth {`#migration-with-api-auth`} +### withApiAuth [#migration-with-api-auth] { -## Migrate from 0.6.11 and below to 0.7.0 {`#migration-0-7`} +## Migrate from 0.6.11 and below to 0.7.0 [#migration-0-7] There are numerous breaking changes in the latest 0.7.0 version of this library. @@ -720,7 +720,7 @@ There are numerous breaking changes in the latest 0.7.0 version of this library. The environment variable prefix is now `PUBLIC_` instead of `VITE_` (e.g., `VITE_SUPABASE_URL` is now `PUBLIC_SUPABASE_URL`). -### Set up the Supabase client {`#migration-set-up-supabase-client-0-7`} +### Set up the Supabase client [#migration-set-up-supabase-client-0-7] -### Initialize the client {`#migration-initialize-client-0-7`} +### Initialize the client [#migration-initialize-client-0-7] -### Set up hooks {`#migration-set-up-hooks-0-7`} +### Set up hooks [#migration-set-up-hooks-0-7] -### Typings {`#migration-typings-0-7`} +### Typings [#migration-typings-0-7] -## `http_get` {`#http_get`} +## `http_get` [#http_get] Creates an HTTP GET request returning the request's ID. HTTP requests are not started until the transaction is committed. @@ -98,7 +98,7 @@ request_id After triggering `http_get`, use [`http_get_result`](#http_get_result) to get the result of the request. -## `http_post` {`#http_post`} +## `http_post` [#http_post] Creates an HTTP POST request with a JSON body, returning the request's ID. HTTP requests are not started until the transaction is committed. @@ -150,7 +150,7 @@ request_id After triggering `http_post`, use [`http_get_result`](#http_get_result) to get the result of the request. -## `http_collect_response` {`#http_collect_response`} +## `http_collect_response` [#http_collect_response] Given a `request_id` reference, retrieves the response. diff --git a/apps/docs/pages/guides/database/full-text-search.mdx b/apps/docs/pages/guides/database/full-text-search.mdx index 075d34fc204..51de6e5bdaa 100644 --- a/apps/docs/pages/guides/database/full-text-search.mdx +++ b/apps/docs/pages/guides/database/full-text-search.mdx @@ -55,7 +55,7 @@ values The functions we'll cover in this guide are: -### `to_tsvector()` {`#to-tsvector`} +### `to_tsvector()` [#to-tsvector] Converts your data into searchable "tokens". `to_tsvector()` stands for "to text search vector". For example: @@ -67,14 +67,14 @@ select to_tsvector('green eggs and ham') Collectively these tokens are called a "document" which Postgres can use for comparisons. -### `to_tsquery()` {`#to-tsquery`} +### `to_tsquery()` [#to-tsquery] Converts a query string into "tokens" to match. `to_tsquery()` stands for "to text search query". This conversion step is important because we will want to "fuzzy match" on keywords. For example if a user searches for "eggs", and a column has the value "egg", we probably still want to return a match. -### Match: `@@` {`#match`} +### Match: `@@` [#match] The `@@` symbol is the "match" symbol for Full Text Search. It returns any matches between a `to_tsvector` result and a `to_tsquery` result. @@ -449,7 +449,7 @@ final result = await client Visit [PostgreSQL: Text Search Functions and Operators](https://www.postgresql.org/docs/current/functions-textsearch.html) to learn about additional query operators you can use to do more advanced `full text queries`, such as: -### Proximity: `<->` {`#proximity`} +### Proximity: `<->` [#proximity] The proximity symbol is useful for searching for terms that are a certain "distance" apart. For example, to find the phrase `big dreams`, where the a match for "big" is followed immediately by a match for "dreams": @@ -538,7 +538,7 @@ final result = await client -### Negation: `!` {`#negation`} +### Negation: `!` [#negation] The negation symbol can be used to find phrases which _don't_ contain a search term. For example, to find records that have the word `big` but not `little`: diff --git a/apps/docs/pages/guides/migrations/firebase-auth.mdx b/apps/docs/pages/guides/migrations/firebase-auth.mdx index 4093651ca85..6377ac83f13 100644 --- a/apps/docs/pages/guides/migrations/firebase-auth.mdx +++ b/apps/docs/pages/guides/migrations/firebase-auth.mdx @@ -12,7 +12,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase - `firestoreusers2json` ([TypeScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/firestoreusers2json.ts), [JavaScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/firestoreusers2json.js)) exports users from an existing Firebase project to a `.json` file on your local system. - `import_users` ([TypeScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/import_users.ts), [JavaScript](https://github.com/supabase-community/firebase-to-supabase/blob/main/auth/import_users.js)) imports users from a saved `.json` file into your Supabase project (inserting those users into the `auth.users` table of your `PostgreSQL` database instance). -## Set up the migration tool {`#set-up-migration-tool`} +## Set up the migration tool [#set-up-migration-tool] 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -36,7 +36,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Under **Connection Info**, copy the Host string and replace the entry in your `supabase-service.json` file. 1. Enter the password you used when you created your Supabase project in the `password` entry in the `supabase-service.json` file. -## Generate a Firebase private key {`#generate-firebase-private-key`} +## Generate a Firebase private key [#generate-firebase-private-key] 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -44,7 +44,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Click **Generate new private key**. 1. Rename the downloaded file to `firebase-service.json`. -## Save your Firebase password hash parameters {`#save-firebase-hash-parameters`} +## Save your Firebase password hash parameters [#save-firebase-hash-parameters] 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Select **Authentication** (Build section) in the sidebar. @@ -64,14 +64,14 @@ hash_config { ## Command line options -### Dump Firestore users to a JSON file {`#dump-firestore-users`} +### Dump Firestore users to a JSON file [#dump-firestore-users] `node firestoreusers2json.js [] []` - `filename.json`: (optional) output filename (defaults to `./users.json`) - `batchSize`: (optional) number of users to fetch in each batch (defaults to 100) -### Import JSON users file to Supabase Auth (PostgreSQL: auth.users) {`#import-json-users-file`} +### Import JSON users file to Supabase Auth (PostgreSQL: auth.users) [#import-json-users-file] `node import_users.js []` diff --git a/apps/docs/pages/guides/migrations/firebase-storage.mdx b/apps/docs/pages/guides/migrations/firebase-storage.mdx index c51fb1c4d75..1516dd2537b 100644 --- a/apps/docs/pages/guides/migrations/firebase-storage.mdx +++ b/apps/docs/pages/guides/migrations/firebase-storage.mdx @@ -12,7 +12,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase 1. Files are downloaded from a Firebase storage bucket to a local filesystem. 2. Files are uploaded from the local filesystem to a Supabase storage bucket. -## Set up the migration tool {`#set-up-migration-tool`} +## Set up the migration tool [#set-up-migration-tool] 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -25,7 +25,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Copy the **Project URL** and update the `SUPABASE_URL` value in `supabase-keys.js`. 1. Under **Project API keys**, copy the **service_role** key and update the `SUPABASE_KEY` value in `supabase-keys.js`. -## Generate a Firebase private key {`#generate-firebase-private-key`} +## Generate a Firebase private key [#generate-firebase-private-key] 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -35,7 +35,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git ## Command line options -### Download Firestore Storage bucket to a local filesystem folder {`#download-firestore-storage-bucket`} +### Download Firestore Storage bucket to a local filesystem folder [#download-firestore-storage-bucket] `node download.js [] [] [] []` @@ -47,7 +47,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git To process in batches using multiple command-line executions, you must use the same parameters with a new `` on subsequent calls. Use the token displayed on the last call to continue the process at a given point. -### Upload files to Supabase Storage bucket {`#upload-to-supabase-storage-bucket`} +### Upload files to Supabase Storage bucket [#upload-to-supabase-storage-bucket] `node upload.js ` diff --git a/apps/docs/pages/guides/migrations/firestore-data.mdx b/apps/docs/pages/guides/migrations/firestore-data.mdx index 72a64ae570b..5e99d591e95 100644 --- a/apps/docs/pages/guides/migrations/firestore-data.mdx +++ b/apps/docs/pages/guides/migrations/firestore-data.mdx @@ -11,7 +11,7 @@ Supabase provides several [tools](https://github.com/supabase-community/firebase The Firestore `collection` is "flattened" and converted to a table with basic columns of one of the following types: `text`, `numeric`, `boolean`, or `jsonb`. If your structure is more complex, you can write a program to split the newly-created `json` file into multiple, related tables before you import your `json` file(s) to Supabase. -## Set up the migration tool {`#set-up-migration-tool`} +## Set up the migration tool [#set-up-migration-tool] 1. Clone the [firebase-to-supabase](https://github.com/supabase-community/firebase-to-supabase) repository: @@ -35,7 +35,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git 1. Under **Connection Info**, copy the Host string and replace the entry in your `supabase-service.json` file. 1. Enter the password you used when you created your Supabase project in the `password` entry in the `supabase-service.json` file. -## Generate a Firebase private key {`#generate-firebase-private-key`} +## Generate a Firebase private key [#generate-firebase-private-key] 1. Log in to your [Firebase Console](https://console.firebase.google.com/project) and open your project. 1. Click the gear icon next to **Project Overview** in the sidebar and select **Project Settings**. @@ -79,7 +79,7 @@ And split it into two files (one table for users and one table for items): ] ``` -### Import JSON file to Supabase (PostgreSQL) {`#import-to-supabase`} +### Import JSON file to Supabase (PostgreSQL) [#import-to-supabase] `node json2supabase.js [] []` diff --git a/apps/docs/pages/guides/migrations/heroku.mdx b/apps/docs/pages/guides/migrations/heroku.mdx index 8c95e05ebf8..51ab83dfb49 100644 --- a/apps/docs/pages/guides/migrations/heroku.mdx +++ b/apps/docs/pages/guides/migrations/heroku.mdx @@ -22,7 +22,7 @@ Alternatively, use the [Heroku to Supabase migration tool](https://migrate.supab > -## Retrieve your Heroku database credentials {`#retrieve-heroku-credentials`} +## Retrieve your Heroku database credentials [#retrieve-heroku-credentials] 1. Log in to your [Heroku account](https://heroku.com) and select the project you want to migrate. 1. Click **Resources** in the menu and select your **Heroku Postgres** database. @@ -33,13 +33,13 @@ Alternatively, use the [Heroku to Supabase migration tool](https://migrate.supab - User (`$HEROKU_USER`) - Password (`$HEROKU_PASSWORD`) -## Retrieve your Supabase Host {`#retrieve-supabase-host`} +## Retrieve your Supabase Host [#retrieve-supabase-host] 1. If you're new to Supabase, [create a project](https://app.supabase.com). 1. Go to the [Database settings](https://app.supabase.com/project/_/settings/database) for your project in the Supabase Dashboard. 1. Under **Connection Info**, note your Host (`$SUPABASE_HOST`). -## Export your Heroku database to a file {`#export-heroku-database`} +## Export your Heroku database to a file [#export-heroku-database] Use `pg_dump` with your Heroku credentials to export your Heroku database to a file (e.g., `heroku_dump.sql`). @@ -49,7 +49,7 @@ pg_dump --clean --if-exists --quote-all-identifiers \ --no-owner --no-privileges > heroku_dump.sql ``` -## Import the database to your Supabase project {`#import-database-to-supabase`} +## Import the database to your Supabase project [#import-database-to-supabase] Use `psql` to import the Heroku database file to your Supabase project. diff --git a/apps/docs/pages/guides/platform/compute-add-ons.mdx b/apps/docs/pages/guides/platform/compute-add-ons.mdx index 9403f03c06a..1aa251dd08b 100644 --- a/apps/docs/pages/guides/platform/compute-add-ons.mdx +++ b/apps/docs/pages/guides/platform/compute-add-ons.mdx @@ -27,7 +27,7 @@ Every project on the Supabase Platform comes with its own dedicated Postgres ins All Postgres instances on Supabase are dedicated applications running inside dedicated virtual machines. However, the underlying hardware resources, for example the physical CPU, may be shared between multiple VMs, but appear to the OS as if it is a dedicated hardware CPU. This is commonly referred to as a vCPU (virtual CPU). Cloud providers use these shared hardware resources to save cost—you can upgrade to a larger compute add-on to guarantee a dedicated physical CPU for your instance. -## Compute upgrades {`#upgrades`} +## Compute upgrades [#upgrades] When considering compute upgrades, assess whether your bottlenecks are hardware-constrained or software-constrained. For example, you may want to look into [optimizing the number of connections](/docs/guides/platform/performance#optimizing-the-number-of-connections) or [examining query performance](/docs/guides/platform/performance#examining-query-performance). When you're happy with your Postgres instance's performance, then you can focus on additional compute resources. For example, you can load test your application in staging to understand your compute requirements. You can also start out on a smaller tier, [create a report](https://app.supabase.com/project/_/reports) in the Dashboard to monitor your CPU utilization, and upgrade later as needed From fcefe80cbf9b8896f02dbafe7e351f869587708d Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Tue, 22 Nov 2022 11:23:54 -0330 Subject: [PATCH 5/5] Fix page footer --- apps/docs/pages/guides/with-nextjs.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/docs/pages/guides/with-nextjs.mdx b/apps/docs/pages/guides/with-nextjs.mdx index e58126e0dd9..df4d8171a4d 100644 --- a/apps/docs/pages/guides/with-nextjs.mdx +++ b/apps/docs/pages/guides/with-nextjs.mdx @@ -729,6 +729,4 @@ At this stage you have a fully functional application! export const Page = ({ children }) => -export default Pag - -e +export default Page