diff --git a/.github/workflows/autofix_linters.yml b/.github/workflows/autofix_linters.yml new file mode 100644 index 00000000000..ca8882d7e04 --- /dev/null +++ b/.github/workflows/autofix_linters.yml @@ -0,0 +1,58 @@ +name: Autofix Linting Checks + +on: + pull_request: + types: + - labeled + +# Cancel old builds on new commit for same workflow + branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + autofix: + runs-on: ubuntu-latest + permissions: + contents: write + if: ${{ github.event_name == 'pull_request' && (github.event.label.name == 'autofix') }} + steps: + - name: Calculate number of commits + run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}" + + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + sparse-checkout: apps + fetch-depth: ${{ env.PR_FETCH_DEPTH }} + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + # Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps + - name: Install required dependencies + run: | + rm package.json + rm package-lock.json + npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst + + - name: Run Prettier in fix mode + run: | + npx prettier --write 'apps/**/*.{js,jsx,ts,tsx,css,md,mdx,json}' + + - name: Commit changes and push to existing branch + run: | + git checkout -- package.json + git checkout -- package-lock.json + git config --global user.name 'github-tidy-bot' + git config --global user.email 'github-tidy-bot@supabase.com' + if [[ `git status --porcelain` ]]; then + echo "[bot] Changes detected, committing." + + echo "[bot] Running in non-squash mode." + git commit -am "ci: Autofix updates from GitHub workflow" + git push + else + echo "[bot] No changes detected, nothing to commit." + fi diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 379248ed601..cc2d29c5659 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -27,7 +27,7 @@ jobs: run: | rm package.json rm package-lock.json - npm i prettier@2 prettier-plugin-sql-cst + npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst - name: Run prettier run: |- npx prettier -c 'apps/**/*.{js,jsx,ts,tsx,css,md,mdx,json}' @@ -50,7 +50,7 @@ jobs: run: | rm package.json rm package-lock.json - npm i prettier@2 prettier-plugin-sql-cst + npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst - name: Run prettier run: |- npx prettier -c 'i18n/**/*.{js,jsx,ts,tsx,css,md,mdx,json}' @@ -68,7 +68,7 @@ jobs: run: | rm package.json rm package-lock.json - npm i prettier@2 prettier-plugin-sql-cst + npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst - name: Run prettier run: |- # Check mdx files which contain sql code blocks diff --git a/apps/database-new/app/[threadId]/[runId]/UserChat.tsx b/apps/database-new/app/[threadId]/[runId]/UserChat.tsx index 8abc0683a6e..f1457b55ff6 100644 --- a/apps/database-new/app/[threadId]/[runId]/UserChat.tsx +++ b/apps/database-new/app/[threadId]/[runId]/UserChat.tsx @@ -138,8 +138,8 @@ const UserChat = ({ message, isLatest, times, run }: UserChatProps) => { {replyDuration !== undefined ? ` with ${replyDuration}s response` : isLoading - ? ', generating response...' - : ''} + ? ', generating response...' + : ''}

)} diff --git a/apps/database-new/app/globals.css b/apps/database-new/app/globals.css index bbe375023cc..11c393d6b2d 100644 --- a/apps/database-new/app/globals.css +++ b/apps/database-new/app/globals.css @@ -8,56 +8,64 @@ @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-Book.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-Book.woff2) format('woff2'), url(/fonts/custom/CustomFont-Book.woff) format('woff'); font-weight: 400; font-style: normal; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-BookItalic.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-BookItalic.woff2) format('woff2'), url(/fonts/custom/CustomFont-BookItalic.woff) format('woff'); font-weight: 400; font-style: italic; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-Medium.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-Medium.woff2) format('woff2'), url(/fonts/custom/CustomFont-Medium.woff) format('woff'); font-weight: 500; font-style: normal; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-MediumItalic.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-MediumItalic.woff2) format('woff2'), url(/fonts/custom/CustomFont-MediumItalic.woff) format('woff'); font-weight: 500; font-style: italic; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-Bold.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-Bold.woff2) format('woff2'), url(/fonts/custom/CustomFont-Bold.woff) format('woff'); font-weight: 700; font-style: 600; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-BoldItalic.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-BoldItalic.woff2) format('woff2'), url(/fonts/custom/CustomFont-BoldItalic.woff) format('woff'); font-style: 600; font-style: italic; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-Black.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-Black.woff2) format('woff2'), url(/fonts/custom/CustomFont-Black.woff) format('woff'); font-weight: 800; font-style: normal; } @font-face { font-family: 'circular'; - src: url(/fonts/custom/CustomFont-BlackItalic.woff2) format('woff2'), + src: + url(/fonts/custom/CustomFont-BlackItalic.woff2) format('woff2'), url(/fonts/custom/CustomFont-BlackItalic.woff) format('woff'); font-weight: 800; font-style: italic; @@ -66,7 +74,8 @@ @font-face { font-family: 'source code pro'; src: url('/fonts/source-code-pro/SourceCodePro-Regular.eot'); - src: url('/fonts/source-code-pro/SourceCodePro-Regular.woff2') format('woff2'), + src: + url('/fonts/source-code-pro/SourceCodePro-Regular.woff2') format('woff2'), url('/fonts/source-code-pro/SourceCodePro-Regular.woff') format('woff'), url('/fonts/source-code-pro/SourceCodePro-Regular.ttf') format('truetype'), url('/fonts/source-code-pro/SourceCodePro-Regular.svg#SourceCodePro-Regular') format('svg'); diff --git a/apps/database-new/package.json b/apps/database-new/package.json index db88150b75c..1fbb366d25e 100644 --- a/apps/database-new/package.json +++ b/apps/database-new/package.json @@ -17,7 +17,7 @@ "common": "*", "config": "*", "dayjs": "^1.11.10", - "eslint-config-next": "^14.0.3", + "eslint-config-next": "^14.1.0", "lodash": "^4.17.21", "lucide-react": "^0.292.0", "next": "^14.0.3", diff --git a/apps/database-new/tsconfig.json b/apps/database-new/tsconfig.json index 881d250a669..2b727367ee7 100644 --- a/apps/database-new/tsconfig.json +++ b/apps/database-new/tsconfig.json @@ -15,15 +15,15 @@ "incremental": true, "plugins": [ { - "name": "next" - } + "name": "next", + }, ], "paths": { "@/*": ["./*"], // handle ui package paths - "@ui/*": ["./../../packages/ui/src/*"] - } + "@ui/*": ["./../../packages/ui/src/*"], + }, }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules"], } diff --git a/apps/database-new/types/supabase.ts b/apps/database-new/types/supabase.ts index 6a883759f1d..7050f57386e 100644 --- a/apps/database-new/types/supabase.ts +++ b/apps/database-new/types/supabase.ts @@ -46,7 +46,7 @@ export interface Database { columns: ['user_id'] referencedRelation: 'users' referencedColumns: ['id'] - } + }, ] } responses_ai: { @@ -92,7 +92,7 @@ export interface Database { columns: ['user_id'] referencedRelation: 'users' referencedColumns: ['id'] - } + }, ] } threads: { @@ -132,7 +132,7 @@ export interface Database { columns: ['user_id'] referencedRelation: 'users' referencedColumns: ['id'] - } + }, ] } } diff --git a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx index fa68260238a..5f2047470bd 100644 --- a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx +++ b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx @@ -64,8 +64,8 @@ export function ComboBox({ {isLoading ? 'Loading...' : options.length === 0 - ? `No ${name} found` - : selectedOptionDisplayName ?? `Select a ${name}...`} + ? `No ${name} found` + : selectedOptionDisplayName ?? `Select a ${name}...`} diff --git a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.tsx b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.tsx index dfe36c3b34d..b316a6cdbb8 100644 --- a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.tsx +++ b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.tsx @@ -98,14 +98,14 @@ function OrgProjectSelector() { const stateSummary: ProjectOrgDataState = isUserLoading ? 'userLoading' : !isLoggedIn - ? 'loggedOut' - : anyIsPending - ? 'loggedIn.dataPending' - : anyIsError - ? 'loggedIn.dataError' - : projects?.length === 0 - ? 'loggedIn.dataSuccess.hasNoData' - : 'loggedIn.dataSuccess.hasData' + ? 'loggedOut' + : anyIsPending + ? 'loggedIn.dataPending' + : anyIsError + ? 'loggedIn.dataError' + : projects?.length === 0 + ? 'loggedIn.dataSuccess.hasNoData' + : 'loggedIn.dataSuccess.hasData' const formattedData: ComboBoxOption[] = useMemo( () => @@ -194,16 +194,16 @@ function BranchSelector() { const stateSummary: BranchesDataState = userLoading ? 'userLoading' : !isLoggedIn - ? 'loggedOut' - : !hasBranches - ? 'loggedIn.noBranches' - : isPending - ? 'loggedIn.branches.dataPending' - : isError - ? 'loggedIn.branches.dataError' - : data.length === 0 - ? 'loggedIn.branches.dataSuccess.noData' - : 'loggedIn.branches.dataSuccess.hasData' + ? 'loggedOut' + : !hasBranches + ? 'loggedIn.noBranches' + : isPending + ? 'loggedIn.branches.dataPending' + : isError + ? 'loggedIn.branches.dataError' + : data.length === 0 + ? 'loggedIn.branches.dataSuccess.noData' + : 'loggedIn.branches.dataSuccess.hasData' const formattedData: ComboBoxOption[] = stateSummary !== 'loggedIn.branches.dataSuccess.hasData' @@ -282,14 +282,14 @@ function VariableView({ variable, className }: { variable: Variable; className?: const stateSummary: VariableDataState = isUserLoading ? 'userLoading' : !isLoggedIn - ? 'loggedOut' - : !ref - ? 'loggedIn.noSelectedProject' - : isPending - ? 'loggedIn.selectedProject.dataPending' - : isError - ? 'loggedIn.selectedProject.dataError' - : 'loggedIn.selectedProject.dataSuccess' + ? 'loggedOut' + : !ref + ? 'loggedIn.noSelectedProject' + : isPending + ? 'loggedIn.selectedProject.dataPending' + : isError + ? 'loggedIn.selectedProject.dataError' + : 'loggedIn.selectedProject.dataSuccess' let variableValue: string = null if (stateSummary === 'loggedIn.selectedProject.dataSuccess') { @@ -319,8 +319,8 @@ function VariableView({ variable, className }: { variable: Variable; className?: stateSummary === 'loggedIn.selectedProject.dataPending' ? 'Loading...' : stateSummary === 'loggedIn.selectedProject.dataSuccess' - ? variableValue - : `YOUR ${prettyFormatVariable[variable].toUpperCase()}` + ? variableValue + : `YOUR ${prettyFormatVariable[variable].toUpperCase()}` } /> diff --git a/apps/docs/components/RealtimeLimitsEstimater.tsx b/apps/docs/components/RealtimeLimitsEstimater.tsx index d8e153c2d3b..822c95f5a83 100644 --- a/apps/docs/components/RealtimeLimitsEstimater.tsx +++ b/apps/docs/components/RealtimeLimitsEstimater.tsx @@ -158,8 +158,8 @@ export default function RealtimeLimitsEstimater({}) { {computeAddOn === 'micro' ? 'Micro' : computeAddOn === 'small' - ? 'Small to medium' - : 'Large to 16XL'} + ? 'Small to medium' + : 'Large to 16XL'} diff --git a/apps/docs/components/reference/RefFunctionSection.tsx b/apps/docs/components/reference/RefFunctionSection.tsx index 733e07030f0..19d14023f54 100644 --- a/apps/docs/components/reference/RefFunctionSection.tsx +++ b/apps/docs/components/reference/RefFunctionSection.tsx @@ -126,14 +126,14 @@ const RefFunctionSection: React.FC = (props) => { const codeBlockLang = example?.code?.startsWith('```js') ? 'js' : example?.code?.startsWith('```ts') - ? 'ts' - : example?.code?.startsWith('```dart') - ? 'dart' - : example?.code?.startsWith('```c#') - ? 'csharp' - : example?.code?.startsWith('```kotlin') - ? 'kotlin' - : 'js' + ? 'ts' + : example?.code?.startsWith('```dart') + ? 'dart' + : example?.code?.startsWith('```c#') + ? 'csharp' + : example?.code?.startsWith('```kotlin') + ? 'kotlin' + : 'js' // ` // import { createClient } from '@supabase/supabase-js' diff --git a/apps/docs/docs/ref/javascript/release-notes.mdx b/apps/docs/docs/ref/javascript/release-notes.mdx index edd38f4a762..e61166d7186 100644 --- a/apps/docs/docs/ref/javascript/release-notes.mdx +++ b/apps/docs/docs/ref/javascript/release-notes.mdx @@ -185,7 +185,7 @@ Supabase.js v2 release notes. We're removing the `signIn()` method in favor of more explicit function signatures: - `signInWithPassword()`, `signInWithOtp()`, and `signInWithOtp()`. + `signInWithPassword()`, `signInWithOtp()`, and `signInWithOAuth()`. diff --git a/apps/docs/generator/legacy.ts b/apps/docs/generator/legacy.ts index 9cb6dced62c..cf066ef1d0a 100644 --- a/apps/docs/generator/legacy.ts +++ b/apps/docs/generator/legacy.ts @@ -259,10 +259,10 @@ function extractParamTypeAsString(paramDefinition) { x.value ? `${x.value}` : x.name - ? `${x.name}` - : x.type - ? `${x.type}` - : '' + ? `${x.name}` + : x.type + ? `${x.type}` + : '' ) .join(' | ') } diff --git a/apps/docs/generator/tsconfig.json b/apps/docs/generator/tsconfig.json index 8615cb5639e..457c226ceae 100644 --- a/apps/docs/generator/tsconfig.json +++ b/apps/docs/generator/tsconfig.json @@ -5,9 +5,9 @@ "noImplicitAny": false, "baseUrl": ".", "paths": { - "~/*": ["./*"] - } + "~/*": ["./*"], + }, }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "exclude": ["node_modules"], } diff --git a/apps/docs/internals/generate-sitemap.mjs b/apps/docs/internals/generate-sitemap.mjs index 52c00e86bbc..c82e2709deb 100644 --- a/apps/docs/internals/generate-sitemap.mjs +++ b/apps/docs/internals/generate-sitemap.mjs @@ -53,7 +53,7 @@ async function generate() { ` - const formatted = prettier.format(sitemap, { + const formatted = await prettier.format(sitemap, { ...prettierConfig, parser: 'html', }) diff --git a/apps/docs/internals/tsconfig.json b/apps/docs/internals/tsconfig.json index de1ecb67a32..3f7e8747893 100644 --- a/apps/docs/internals/tsconfig.json +++ b/apps/docs/internals/tsconfig.json @@ -7,9 +7,9 @@ "resolveJsonModule": true, "baseUrl": ".", "paths": { - "~/*": ["./*"] - } + "~/*": ["./*"], + }, }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "exclude": ["node_modules"], } diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index 0b63909f289..ed1447aa80c 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -201,8 +201,8 @@ const MobileHeader = memo(function MobileHeader() { {mobileMenuOpen ? 'Close' : menuLevel - ? levelsData[menuLevel].name - : levelsData['home'].name} + ? levelsData[menuLevel].name + : levelsData['home'].name} ) @@ -267,7 +267,7 @@ const Container = memo(function Container(props: PropsWithChildren) { id="docs-content-container" className={[ // 'overflow-x-auto', - 'w-full h-screen transition-all ease-out', + 'w-full transition-all ease-out', // 'absolute lg:relative', mobileMenuOpen ? 'ml-[75%] sm:ml-[50%] md:ml-[33%] overflow-hidden' : 'overflow-auto', // desktop override any margin styles @@ -294,7 +294,6 @@ const NavContainer = memo(function NavContainer() { 'lg:left-0', 'transition-all', 'top-0', - 'h-screen', 'flex flex-col ml-0', ].join(' ')} > @@ -352,8 +351,8 @@ const SiteLayout = ({ children }: PropsWithChildren<{}>) => { Supabase Docs -
-
+
+
diff --git a/apps/docs/package.json b/apps/docs/package.json index 0883cf3331c..8dc8eede5e3 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -39,7 +39,7 @@ "gray-matter": "^4.0.3", "hast-util-has-property": "^2.0.1", "isbot": "^3.6.5", - "jsrsasign": "^10.5.26", + "jsrsasign": "^11.0.0", "lodash": "^4.17.21", "markdown-toc": "^1.2.0", "mdast": "^3.0.0", diff --git a/apps/docs/pages/_app.tsx b/apps/docs/pages/_app.tsx index 498dd08d20e..cb3937d1f05 100644 --- a/apps/docs/pages/_app.tsx +++ b/apps/docs/pages/_app.tsx @@ -191,16 +191,18 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { <> - - - - - +
+ + + + + +
diff --git a/apps/docs/pages/guides/ai/examples/headless-vector-search.mdx b/apps/docs/pages/guides/ai/examples/headless-vector-search.mdx index 9267986b634..78c59abc87b 100644 --- a/apps/docs/pages/guides/ai/examples/headless-vector-search.mdx +++ b/apps/docs/pages/guides/ai/examples/headless-vector-search.mdx @@ -37,7 +37,7 @@ There are 3 steps to build similarity search inside your documentation: ### Prepare your database -To prepare, create a [new Supabase project](https://database.new) and store the database and API credentials, which you can find in the project [settings](https://supabase.com/dashboard/_/settings). +To prepare, create a [new Supabase project](https://database.new) and store the database and API credentials, which you can find in the project [settings](https://supabase.com/dashboard/project/_/settings). Now we can use the [Headless Vector Search](https://github.com/supabase/headless-vector-search#set-up) instructions to set up the database: diff --git a/apps/docs/pages/guides/ai/google-colab.mdx b/apps/docs/pages/guides/ai/google-colab.mdx index ef9cb7325f5..2f6cca0ea68 100644 --- a/apps/docs/pages/guides/ai/google-colab.mdx +++ b/apps/docs/pages/guides/ai/google-colab.mdx @@ -39,7 +39,7 @@ pip install vecs ## Connect to your database -Find the Postgres pooler connection string for your Supabase project in the [database settings](https://supabase.com/dashboard/_/settings/database) of the dashboard. Copy the "URI" format, which should look something like `postgres://postgres.xxxx:password@xxxx.pooler.supabase.com:6543/postgres` +Find the Postgres pooler connection string for your Supabase project in the [database settings](https://supabase.com/dashboard/project/_/settings/database) of the dashboard. Copy the "URI" format, which should look something like `postgres://postgres.xxxx:password@xxxx.pooler.supabase.com:6543/postgres` Create a new code block below the install block (`ctrl+m b`) and add the following code using the Postgres URI you copied above: diff --git a/apps/docs/pages/guides/ai/integrations/llamaindex.mdx b/apps/docs/pages/guides/ai/integrations/llamaindex.mdx index b1aa7f80b2a..23bfd749a96 100644 --- a/apps/docs/pages/guides/ai/integrations/llamaindex.mdx +++ b/apps/docs/pages/guides/ai/integrations/llamaindex.mdx @@ -1,3 +1,4 @@ +import { Admonition } from 'ui' import Layout from '~/layouts/DefaultGuideLayout' export const meta = { @@ -46,7 +47,19 @@ DB_CONNECTION = "postgresql://:@:/" vx = vecs.create_client(DB_CONNECTION) ``` -Replace the `DB_CONNECTION` with your own connection string for your database, which you set up in first step of this guide. +Replace the `DB_CONNECTION` with your own connection string for your database. You can find the Postgres connection string in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database) of your Supabase project. + + + +SQLAlchemy requires the connection string to start with `postgresql://` (instead of `postgres://`). Don't forget to rename this after copying the string from the dashboard. + + + + + +You must use the "connection pooling" string (domain ending in `*.pooler.supabase.com`) with Google Colab since Colab does not support IPv6. + + ## Stepping through the notebook diff --git a/apps/docs/pages/guides/ai/python-clients.mdx b/apps/docs/pages/guides/ai/python-clients.mdx index 6e6695d3592..563a5e1d7e7 100644 --- a/apps/docs/pages/guides/ai/python-clients.mdx +++ b/apps/docs/pages/guides/ai/python-clients.mdx @@ -11,6 +11,12 @@ As described in [Structured & Unstructured Embeddings](/docs/guides/ai/structure For data science or ephemeral workloads, the [Supabase Vecs](https://supabase.github.io/vecs/) client gets you started quickly. All you need is a connection string and vecs handles setting up your database to store and query vectors with associated metadata. + + +You can get your connection string from the [**Database Settings**](https://supabase.com/dashboard/project/_/settings/database) page in your dashboard. Make sure to check **Use connection pooling**, then copy the URI. Also, change the URI scheme from `postgres` to `postgresql`. `vecs` uses SQLAlchemy under the hood, which only supports `postgresql` as a dialect. + + + For production python applications with version controlled migrations, we recommend adding first class vector support to your toolchain by [registering the vector type with your ORM](https://github.com/pgvector/pgvector-python). pgvector provides bindings for the most commonly used SQL drivers/libraries including Django, SQLAlchemy, SQLModel, psycopg, asyncpg and Peewee. export const Page = ({ children }) => diff --git a/apps/docs/pages/guides/ai/quickstarts/face-similarity.mdx b/apps/docs/pages/guides/ai/quickstarts/face-similarity.mdx index 160ed479b6d..36694ba9320 100644 --- a/apps/docs/pages/guides/ai/quickstarts/face-similarity.mdx +++ b/apps/docs/pages/guides/ai/quickstarts/face-similarity.mdx @@ -1,5 +1,5 @@ +import { Admonition } from 'ui' import Layout from '~/layouts/DefaultGuideLayout' - export const meta = { id: 'ai-vecs-python-client', title: 'Face similarity search', @@ -43,7 +43,19 @@ DB_CONNECTION = "postgresql://:@:/" vx = vecs.create_client(DB_CONNECTION) ``` -Replace the `DB_CONNECTION` with your own connection string for your database, which you set up in first step of this guide. +Replace the `DB_CONNECTION` with your own connection string for your database. You can find the Postgres connection string in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database) of your Supabase project. + + + +SQLAlchemy requires the connection string to start with `postgresql://` (instead of `postgres://`). Don't forget to rename this after copying the string from the dashboard. + + + + + +You must use the "connection pooling" string (domain ending in `*.pooler.supabase.com`) with Google Colab since Colab does not support IPv6. + + ## Stepping through the notebook diff --git a/apps/docs/pages/guides/ai/quickstarts/hello-world.mdx b/apps/docs/pages/guides/ai/quickstarts/hello-world.mdx index d612ed23d86..88d4b42ef5c 100644 --- a/apps/docs/pages/guides/ai/quickstarts/hello-world.mdx +++ b/apps/docs/pages/guides/ai/quickstarts/hello-world.mdx @@ -1,3 +1,4 @@ +import { Admonition } from 'ui' import Layout from '~/layouts/DefaultGuideLayout' export const meta = { @@ -43,7 +44,19 @@ DB_CONNECTION = "postgresql://:@:/" vx = vecs.create_client(DB_CONNECTION) ``` -Replace the `DB_CONNECTION` with your own connection string for your database, which you set up in first step of this guide. +Replace the `DB_CONNECTION` with your own connection string for your database. You can find the Postgres connection string in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database) of your Supabase project. + + + +SQLAlchemy requires the connection string to start with `postgresql://` (instead of `postgres://`). Don't forget to rename this after copying the string from the dashboard. + + + + + +You must use the "connection pooling" string (domain ending in `*.pooler.supabase.com`) with Google Colab since Colab does not support IPv6. + + ## Stepping through the notebook diff --git a/apps/docs/pages/guides/ai/quickstarts/text-deduplication.mdx b/apps/docs/pages/guides/ai/quickstarts/text-deduplication.mdx index d15cbbd1289..afa8cf81b49 100644 --- a/apps/docs/pages/guides/ai/quickstarts/text-deduplication.mdx +++ b/apps/docs/pages/guides/ai/quickstarts/text-deduplication.mdx @@ -1,5 +1,6 @@ -import Layout from '~/layouts/DefaultGuideLayout' +import { Admonition } from 'ui' import HuggingFaceDeployment from '~/components/MDX/ai/quickstart_hf_deployment.mdx' +import Layout from '~/layouts/DefaultGuideLayout' export const meta = { id: 'ai-vecs-python-client', @@ -44,7 +45,19 @@ DB_CONNECTION = "postgresql://:@:/" vx = vecs.create_client(DB_CONNECTION) ``` -Replace the `DB_CONNECTION` with your own connection string for your database, which you set up in first step of this guide. +Replace the `DB_CONNECTION` with your own connection string for your database. You can find the Postgres connection string in the [Database Settings](https://supabase.com/dashboard/project/_/settings/database) of your Supabase project. + + + +SQLAlchemy requires the connection string to start with `postgresql://` (instead of `postgres://`). Don't forget to rename this after copying the string from the dashboard. + + + + + +You must use the "connection pooling" string (domain ending in `*.pooler.supabase.com`) with Google Colab since Colab does not support IPv6. + + ## Stepping through the notebook diff --git a/apps/docs/pages/guides/auth/auth-password-reset.mdx b/apps/docs/pages/guides/auth/auth-password-reset.mdx deleted file mode 100644 index 7490f1edb1f..00000000000 --- a/apps/docs/pages/guides/auth/auth-password-reset.mdx +++ /dev/null @@ -1,250 +0,0 @@ -import Layout from '~/layouts/DefaultGuideLayout' -import { Accordion } from 'ui' - -export const meta = { - id: 'auth-password-reset', - title: 'Password Reset', - description: 'How to reset password with Supabase Auth', -} - -- Send email for password reset using [`.resetPasswordForEmail`](/docs/reference/javascript/auth-resetpasswordforemail) while providing a `redirectTo` parameter -- Email link will work as a magic link and log the user in then take them to the url specified in the `redirectTo` parameter -- Create form to update the password and call the [`.updateUser`](/docs/reference/javascript/auth-updateuser) method with the new password - -## Single Page Application (SPA) - -### Sending password reset email - - - - -Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/javascript/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectTo` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user. - -```js -await supabase.auth.resetPasswordForEmail('hello@example.com', { - redirectTo: 'http://example.com/account/update-password', -}) -``` - - - - -Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user. - -```kotlin -supabase.auth.resetPasswordForEmail( - email = "hello@example.com", - redirectUrl = "http://example.com/account/update-password" -) -``` - -If you are on one of the Kotlin targets that have built-in support for redirect url handling like Android, you may want to checkout [OAuth and OTP link verification](https://supabase.com/docs/reference/kotlin/initializing). - - - - -### Email link - -The email link you receive will work like a magic link. This way when you click the link you will be logged into the website. Since we passed a redirect URL to the [`.resetPasswordForEmail`](https://supabase.com/docs/reference/javascript/auth-resetpasswordforemail) method the user should be sent to the update password page. - -### Update password - - - - -To update the password we call the [`.updateUser`](/docs/reference/javascript/auth-updateuser) method and pass along the new password to this method. - -```js -await supabase.auth.updateUser({ password: new_password }) -``` - - - - -To update the password we call the [`.modifyUser`](/docs/reference/kotlin/auth-updateuser) method and pass along the new password to this method. - -```kotlin -supabase.auth.modifyUser { - password = "new_password" -} -``` - - - - -## Server-Side Rendering (SSR) - -### Sending password reset email - - - - -Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/javascript/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectTo` which we will use to pass an absolute URL to the callback page along with a query parameter to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user. - -```js -await supabase.auth.resetPasswordForEmail('hello@example.com', { - redirectTo: 'http://example.com/api/auth/callback?next=/account/update-password', -}) -``` - - - -We are using `next` as our query parameter, but this can name whatever you like. - - - - - - -Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user. - -```kotlin -supabase.auth.resetPasswordForEmail( - email = "hello@example.com", - redirectUrl = "http://example.com/api/auth/callback?next=/account/update-password" -) -``` - -If you are on one of the Kotlin targets that have built-in support for redirect url handling like Android, you may want to checkout [OAuth and OTP link verification](https://supabase.com/docs/reference/kotlin/initializing). - - - - -### Email link - -The email link you receive will behave like a magic link. When the link is clicked you will be sent to the `redirectTo` URL you specified that points to the path with the exchange code. - -### Exchange authorization code - - - - -After redirecting to the server page, we need to retrieve the code from the query parameter called `code` and pass it to the `.exchangeCodeForSession` function. - -```js -// api/auth/callback.ts - -// The code is retrieved from the query parameter - use whichever mechanism is recommended -// for your app/framework. This is just an example. -const code = url.searchParams.get('code') - -// call the Supabase API to exchange the code for a session -await supabase.auth.exchangeCodeForSession(code) -``` - - - -The query parameter is always `code` for the authorization code returned from the Supabase API - - - -We will also need to check for the `next` query parameter to redirect the user to the update password page. - -```ts -// api/auth/callback.ts - -// The password page path is retrieved from the query parameter - use whichever mechanism is recommended -// for your app/framework. This is just an example. -const next = url.searchParams.get('next') - -// using Next.js API response object in this example -res.redirect(next) -``` - - - - -Here is an example on Android: - -```kotlin -//Wherever you initialize your SupabaseClient: -val client = createSupabaseClient(supabaseUrl, supabaseKey) { - install(GoTrue) { - flowType = FlowType.PKCE - scheme = "exampleApp" - host = "callback" - } -} -``` - -```xml - - - - - - - - -``` - -```kotlin -//MainActivity.kt -override fun onCreate() { - client.handleDeeplinks(intent) -} -``` - -That's it! `supabase-kt` will take care of parsing and importing the session. Other targets are similar, you can check [OAuth and OTP link verification](https://supabase.com/docs/reference/kotlin/initializing) for more information. - - - - -### Update password - - - - -To update the password we call the [`.updateUser`](/docs/reference/javascript/auth-updateuser) method and pass along the new password to this method. - -```js -await supabase.auth.updateUser({ password: new_password }) -``` - - - - -To update the password we call the [`.modifyUser`](/docs/reference/kotlin/auth-updateuser) method and pass along the new password to this method. - -```kotlin -supabase.auth.modifyUser { - password = "new_password" -} -``` - - - - -export const Page = ({ children }) => - -export default Page diff --git a/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx b/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx index f0e4ef72106..dd6d8a4e16b 100644 --- a/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx +++ b/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx @@ -98,6 +98,12 @@ dotenv.config() Creating a Supabase client with the `ssr` package automatically configures it to use cookies. This means your user's session is available throughout the entire Next.js stack - client, server, App Router, Pages Router. It just works! + + +For the client utility functions, it is recommended to create them in a separate `/utils/supabase` folder. That way, you can import them as `client` into any component or page that needs access to Supabase. For further information, you can look at the [Next.js Auth Guide](/docs/guides/auth/server-side/nextjs). + + + Magic Link

Follow this link to login:

-

Log In

+

Log In

``` **Change Email Address template** diff --git a/apps/docs/pages/guides/auth/server-side/nextjs.mdx b/apps/docs/pages/guides/auth/server-side/nextjs.mdx index 99247eaca9c..41f9f584954 100644 --- a/apps/docs/pages/guides/auth/server-side/nextjs.mdx +++ b/apps/docs/pages/guides/auth/server-side/nextjs.mdx @@ -155,10 +155,10 @@ export function createClient(cookieStore: ReturnType) { return cookieStore.get(name)?.value }, set(name: string, value: string, options: CookieOptions) { - return cookieStore.set({ name, value, ...options }) + cookieStore.set({ name, value, ...options }) }, remove(name: string, options: CookieOptions) { - return cookieStore.set({ name, value: '', ...options }) + cookieStore.set({ name, value: '', ...options }) }, }, } @@ -284,9 +284,7 @@ export const config = { Create a login page for your app. Use a Server Action to call the Supabase signup function. -If you have email confirmations turned on (the default), a new user will receive a confirmation email after signing up. When they click the link, they are directed to the Auth callback route at `auth/confirm` with a secure code. A Route Handler at this route finishes the signup process by exchanging the code for an Auth token. - -Since Supabase is being called from an Action and a Route Handler, use the client defined in `@/utils/supabase/actions.ts`. +Since Supabase is being called from an Action, use the client defined in `@/utils/supabase/actions.ts`. @@ -369,7 +367,39 @@ export default function ErrorPage() { } ``` -```ts app/auth/confirm/route.ts + + + + + + + + + + +If you have email confirmation turned on (the default), a new user will receive an email confirmation after signing up. + +Change the email template to support a server-side authentication flow. + +Go to the [Auth templates](https://supabase.com/dashboard/project/_/auth/templates) page in your dashboard. In each email template, change `{{ .ConfirmationURL }}` to `{{ .SiteURL }}/auth/callback?token_hash={{ .TokenHash }}&type=signup`. + + + + + + + + + +Create a Route Handler for `auth/callback`. When a user clicks their confirmation email link, exchange their secure code for an Auth token. + +Since this is a Router Handler, use the Supabase client from `@/utils/supabase/actions.ts`. + + + + + +```ts app/auth/callback/route.ts import { type EmailOtpType } from '@supabase/supabase-js' import { cookies } from 'next/headers' import { type NextRequest, NextResponse } from 'next/server' @@ -408,13 +438,11 @@ export async function GET(request: NextRequest) { } ``` - - - + @@ -676,10 +704,10 @@ export default function createClient(req: NextApiRequest, res: NextApiResponse) return req.cookies[name] }, set(name: string, value: string, options: CookieOptions) { - res.setHeader('Set-Cookie', serialize(name, value, options)) + res.appendHeader('Set-Cookie', serialize(name, value, options)) }, remove(name: string, options: CookieOptions) { - res.setHeader('Set-Cookie', serialize(name, '', options)) + res.appendHeader('Set-Cookie', serialize(name, '', options)) }, }, } @@ -772,11 +800,11 @@ export default function LoginPage() { -If you have email confirmation turned on (the default), a new user will receive an email confirmation after signing up. By default, the link in this email goes to the path `auth/confirm`. +If you have email confirmation turned on (the default), a new user will receive an email confirmation after signing up. -Change this to `api/auth/confirm`. +Change the email template to support a server-side authentication flow. -Go to the [Auth templates](https://supabase.com/dashboard/project/_/auth/templates) page in your dashboard. In each email template, change `{{ .SiteURL }}/auth/confirm` to `{{ .SiteURL }}/api/auth/confirm`. +Go to the [Auth templates](https://supabase.com/dashboard/project/_/auth/templates) page in your dashboard. In each email template, change `{{ .ConfirmationURL }}` to `{{ .SiteURL }}/api/auth/callback?token_hash={{ .TokenHash }}&type=signup`. @@ -786,7 +814,7 @@ Go to the [Auth templates](https://supabase.com/dashboard/project/_/auth/templat -Create an API route for `api/auth/confirm`. When a user clicks their confirmation email link, exchange their secure code for an Auth token. +Create an API route for `api/auth/callback`. When a user clicks their confirmation email link, exchange their secure code for an Auth token. Since this is an API route, use the Supabase client from `@/utils/supabase/api.ts`. @@ -796,7 +824,7 @@ Since this is an API route, use the Supabase client from `@/utils/supabase/api.t -```ts pages/api/auth/confirm.tsx +```ts pages/api/auth/callback.tsx import { type EmailOtpType } from '@supabase/supabase-js' import type { NextApiRequest, NextApiResponse } from 'next' diff --git a/apps/docs/pages/guides/auth/social-login/auth-apple.mdx b/apps/docs/pages/guides/auth/social-login/auth-apple.mdx index d121be46da3..f2a5385977c 100644 --- a/apps/docs/pages/guides/auth/social-login/auth-apple.mdx +++ b/apps/docs/pages/guides/auth/social-login/auth-apple.mdx @@ -200,9 +200,9 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app, - ## Using native sign in with Apple in Flutter + ## Apple sign in on iOS and macOS - You can perform Apple sign in using the [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package on Flutter. + You can perform Apple sign in using the [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package on Flutter apps running on iOS or macOS. Follow the instructions in the package README to set up native Apple sign in on iOS and macOS. Once the setup is complete on the Flutter app, add the bundle ID of your app to your Supabase dashboard in `Authentication -> Providers -> Apple` in order to register your app with Supabase. @@ -249,6 +249,32 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app, + ## Apple sign in on Android, Web, Windows and Linux + + For platforms that doesn't support native Apple sign in, you can use the `signInWithOAuth()` method to perform the Apple sign in. + This method of signing in is web based, and will open a browser window to perform the sign in. For non-web platforms, the user is brought back to the app via [deep linking](/docs/guides/auth/native-mobile-deep-linking?platform=flutter). + + ```dart + supabase.auth.signInWithOAuth( + OAuthProvider.apple, + redirectTo: 'my-scheme://login-callback', + ); + ``` + + This call takes the user to Apple's consent screen. Once the flow ends, the user's profile information is exchanged and validated with Supabase Auth before it redirects back to your Flutter application with an access and refresh token representing the user's session. + + ### Configuration [#flutter-configuration-web] + + You will require the following information: + + 1. Your Apple Developer account's **Team ID**, which is an alphanumeric string of 10 characters that uniquely identifies the developer of the app. It's often easily accessible in the upper right-side menu on the Apple Developer Console. + 2. Register email sources for _Sign in with Apple for Email Communication_ which can be found in the [Services](https://developer.apple.com/account/resources/services/list) section of the Apple Developer Console. + 3. An **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple once you create an App ID in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._) + 4. A **Services ID** which uniquely identifies the web services provided by the app you registered in the previous step. You can create a new Services ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/serviceId) section in the Apple Developer Console (use the filter menu in the upper right side to see all Services IDs). These usually are a reverse domain name string, for example `com.example.app.web`. + 5. Configure Website URLs for the newly created **Services ID**. The web domain you should use is the domain your Supabase project is hosted on. This is usually `.supabase.co` while the redirect URL is `https://.supabase.co/auth/v1/callback`. + 6. Create a signing **Key** in the [Keys](https://developer.apple.com/account/resources/authkeys/list) section of the Apple Developer Console. You can use this key to generate a secret key using the tool below, which is added to your Supabase project's Auth configuration. Make sure you safely store the `AuthKey_XXXXXXXXXX.p8` file. If you ever lose access to it, or make it public accidentally please revoke it from the Apple Developer Console and create a new one immediately. You will have to generate a new secret key using this file every 6 months, so make sure you schedule a recurring reminder in your calendar! + 7. Finally, add the information you configured above to the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers). + diff --git a/apps/docs/pages/guides/auth/social-login/auth-spotify.mdx b/apps/docs/pages/guides/auth/social-login/auth-spotify.mdx index a4647b8c554..0bd365876c8 100644 --- a/apps/docs/pages/guides/auth/social-login/auth-spotify.mdx +++ b/apps/docs/pages/guides/auth/social-login/auth-spotify.mdx @@ -52,6 +52,14 @@ Under `Redirect URIs`: ## Add login code to your client app +The following outlines the steps to sign in using Spotify with Supabase Auth. + +1. Call the signin method from the client library. +1. The user is redirected to the Spotify login page. +1. After completing the sign-in process, the user will be redirected to your app with an error that says the email address needs to be confirmed. Simultaneously the user receives a confirmation email from Supabase Auth. +1. The user clicks the confirmation link in the email. +1. The user is brought back to the app and is now signed in. + -Starting on , direct database connections will start resolving to an IPv6 address. If you connect to your database using the REST and GraphQL endpoints, this doesn't affect you. If you use the database connection string, see the GitHub discussion on [how to prepare for IPv6](https://github.com/orgs/supabase/discussions/17817). +Direct database connections will start resolving to an IPv6 address. Starting from January 26, 2024, projects will be gradually migrated to this behavior. If you connect to your database using the REST or GraphQL endpoints, this doesn't affect you. If you use the database connection string, see the GitHub discussion on [how to prepare for IPv6](https://github.com/orgs/supabase/discussions/17817). @@ -31,37 +31,61 @@ Supabase provides auto-updating Data APIs. These are the easiest way to get star ## Connection pooler -Every Supabase project comes with a connection pooler for managing connections to your Postgres database. +A "connection pool" is a system (external to Postgres) which manages Postgres connections. -A connection pooler is useful for managing a large number of _temporary_ connections - for example, if you are using Prisma, Drizzle, Kysely, or anything deployed to a Serverless environment (AWS Lambdas or Edge Functions). Supabase's connection pooler also supports ipv4 out of the box. +When a client makes a request, the pooler "allocates" an available connection to the client. When the client transaction or session is completed the connection is returned to the pool and is free to be used by another client. + +
+ + +
Connecting to the database directly vs using a Connection Pooler
+
+ +Every Supabase project comes with a connection pooler for managing connections to your database. The pooler provides 2 important services: + +1. It manages connections for applications that connect and disconnect from the database frequently. For example, serverless functions and ORMs such as Prisma, Drizzle, and Kysely often make and drop connections to the database. If they connected directly each time, they would quickly exhaust your database server's memory. To connect to your database efficiently with such tools, you need a pooler. +2. It provides an IPv4 endpoint to connect to your database, which you can use if your network provider doesn't support IPv6. This is unlike the direct database connection, which resolves to an IPv6 address, unless you've enabled the [IPv4 add-on](https://supabase.com/docs/guides/platform/ipv4-address). + + + +The connection pooler is available in 2 modes: `Transaction` and `Session`. + + + +Transaction mode is recommended if you are connecting from serverless environments. A connection is assigned to the client for the duration of a transaction. Two consecutive transactions from the same client can be executed over two different connections. Some session-based Postgres features such as prepared statements are _not available_ with this option. + +Session mode is similar to connecting to your database directly. There is full support for prepared statements in this mode. When a new client connects, a connection is assigned to the client until it disconnects. You might run into pooler connection limits since the connection is held till the client disconnects. You can find the connection pool config in the [Database settings](/dashboard/project/_/settings/database) inside the dashboard: 1. Go to the `Settings` section. 2. Click `Database`. -3. Under `Connect to your database via connection pooling`, copy your `Connection string`. +3. Under `Connection string`, make sure `Use connection pooling` is checked. Copy the URI. ## Direct connections -You can use a direct connection to connect directly to your Postgres database. By default, this connection uses ipv6, which isn't supported by all network providers. If you need an ipv4 address, use the [connection pooler](#connection-pooler) instead. +You can also use a direct connection to connect directly to your Postgres database. By default, you can connect to it via IPv6, which isn't supported by all networks. If you need an IPv4 address, use the [connection pooler](#connection-pooler) instead or enable the [IPv4 add-on](https://supabase.com/docs/guides/platform/ipv4-address). You can find the direct connection string in the [Database settings](https://supabase.com/dashboard/project/_/settings/database) inside the dashboard: 1. Go to the `Settings` section. 2. Click `Database`. -3. Under `Connect to your database directly`, copy your `Connection string`. +3. Under `Connection string`, make sure `Use connection pooling` is unchecked. Copy the URI. ## Choosing a connection method -- The Data APIs provide programmatic access and have [built-in connection pooling](https://postgrest.org/en/stable/references/connection_pool.html). You can use these for all browser and application interactions. We recommend using these wherever possible. -- A "connection pooler" is a tool which keeps connections "alive". You should use this for serverless functions and tools which disconnect from the database frequently, like Prisma, Drizzle, Kysely, etc. You should also use this if your network doesn't support ipv6. -- A "direct connection" is Postgres' native connection system. You can use this for tools which are always alive, such as long-running server, as long as your network supports ipv6. - -Why would you use a connection pool? Primarily because the way that Postgres handles connections isn't very scalable for a large number of _temporary_ connections. You can use these simple questions to determine which connection method to use: - -- Are you on a network that doesn't support ipv6? Use the connection pooler. -- Are you connecting to your database and then _disconnecting_ immediately (e.g. a serverless environment)? Use the connection pooler. -- Are you connecting to a database and _maintaining_ a connection, and does your network support ipv6? If yes, use a direct connection. +- Are you performing operations supported by the Data APIs? We recommend using the APIs. +- Are you connecting to your database and then _disconnecting_ immediately (for example, are you running your code in a serverless environment)? Use the connection pooler in transaction mode. +- Are you on a network that doesn't support IPv6? Use the connection pooler. (If you need a long-lived connection, for example for prepared statements, use session mode.) +- Are you connecting to your database and _maintaining_ a connection, and does your network support IPv6? Use a direct connection. ## Connecting with SSL @@ -108,7 +132,7 @@ You can obtain your connection info and Server root certificate from your applic - ```ts + ```ts schema.ts import { pgTable, serial, text, varchar } from "drizzle-orm/pg-core"; export const users = pgTable('users', { @@ -126,24 +150,25 @@ You can obtain your connection info and Server root certificate from your applic - Connect to your database using the Connection Pooler for serverless environments, and the Direct Connection for long-running servers. + Connect to your database using the Connection Pooler. + + In your [`Database Settings`](https://supabase.com/dashboard/project/_/settings/database), make sure `Use connection pooler` is checked, then copy the URI and save it as the `DATABASE_URL` environment variable. Remember to replace the password placeholder with your actual database password. - ```ts + ```ts db.ts + import 'dotenv/config' + import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' - import { users } from './schema' const connectionString = process.env.DATABASE_URL // Disable prefetch as it is not supported for "Transaction" pool mode - const client = postgres(connectionString, { prepare: false }) - const db = drizzle(client); - - const allUsers = await db.select().from(users); + export const client = postgres(connectionString, { prepare: false }) + export const db = drizzle(client); ``` @@ -168,7 +193,16 @@ You can obtain your connection info and Server root certificate from your applic - ![Register a new postgres server.](/docs/img/guides/database/register-server-pgAdmin.png) + + @@ -184,7 +218,7 @@ You can obtain your connection info and Server root certificate from your applic - ![Name Postgres Server.](/docs/img/guides/database/name-pg-server.png) + ![Name Postgres Server.](/docs/img/guides/database/connecting-to-postgres/pgadmin/name-pg-server.png) @@ -194,13 +228,13 @@ You can obtain your connection info and Server root certificate from your applic - Add the connection info. You can use the "Direct connection" config, which you can find in your Supabase dashboard. + Add the connection info. Go to your [`Database Settings`](https://supabase.com/dashboard/project/_/settings/database). Make sure `Use connection pooling` is enabled. Switch the connection mode to `Session` and copy your connection parameters. - ![Add Connection Info.](/docs/img/guides/database/add-pg-server-conn-info.png) + ![Add Connection Info.](/docs/img/guides/database/connecting-to-postgres/pgadmin/add-pg-server-conn-info.png) @@ -216,7 +250,7 @@ You can obtain your connection info and Server root certificate from your applic - ![Add Connection Info.](/docs/img/guides/database/add-ssl-config-parameter.png) + ![Add Connection Info.](/docs/img/guides/database/connecting-to-postgres/pgadmin/database-settings-host.png) @@ -228,10 +262,12 @@ You can obtain your connection info and Server root certificate from your applic [`psql`](https://www.postgresql.org/docs/current/app-psql.html) is a command-line tool that comes with Postgres. -Assuming you've downloaded your SSL certificate to `$HOME/Downloads/prod-supabase.cer`, and your host address is `db.ref.supabase.co` you connect to your database via SSL: +Download your [SSL certificate](#connecting-with-ssl) to `/path/to/prod-supabase.cer`. + +Find your connection settings. Go to your [`Database Settings`](https://supabase.com/dashboard/project/_/settings/database) and make sure `Use connection pooling` is checked. Change the connection mode to `Session`, and copy the parameters into the connection string: ```shell -psql "sslmode=verify-full sslrootcert=$HOME/Downloads/prod-supabase.cer host=db.ref.supabase.co dbname=postgres user=postgres" +psql "sslmode=verify-full sslrootcert=/path/to/prod-supabase.cer host=[CLOUD_PROVIDER]-0-[REGION].pooler.supabase.com dbname=postgres user=postgres.[PROJECT_REF]" ``` ### Connecting with Prisma @@ -266,7 +302,9 @@ Refer to our [Prisma integration guide](https://supabase.com/partners/integratio - Create a `db.js` file with the connection details. Use the Connection Pooler for serverless environments, and the Direct Connection for long-running servers. + Create a `db.js` file with the connection details. + + To get your connection details, go to your [`Database Settings`](https://supabase.com/dashboard/project/_/settings/database). Make sure `Use connection pooling` is enabled. Choose `Transaction Mode` if you're on a platform with transient connections, such as a serverless function, and `Session Mode` if you have a long-lived connection. Copy the URI and save it as the environment variable `DATABASE_URL`. @@ -316,39 +354,30 @@ Refer to our [Prisma integration guide](https://supabase.com/partners/integratio -## How connection pooling works +## Troubleshooting Supavisor -A "connection pool" is a system (external to Postgres) which manages Postgres connections. +Connection pooler logs are found [here](https://supabase.com/dashboard/project/_/logs/pooler-logs). The following are common errors and their solutions: -When a client makes a request, the pooler "allocates" an available connection to the client. When the client transaction or session is completed the connection is returned to the pool and is free to be used by another client. +- Max client connections reached + This error happens when the number of connections to Supavisor is more than [the allowed limit of your compute add-on](https://supabase.com/docs/guides/platform/compute-add-ons). Upgrade the database to a higher compute add-on to increase the number of Supavisor connections. -![Connection pooling](/docs/img/guides/database/connection-pool.png) +- Connection failed \{:error, :eaddrnotavail} to 'db.xxx.supabase.co':5432 + Supavisor cannot connect to the customer database. This is usually caused if the target database is unable to respond. -There are several pool modes, each handling connections differently: +- Connection failed \{:error, :nxdomain} to 'db.xxx.supabase.co':5432 + Supavisor cannot connect to the customer database. This is usually caused if the target database is unable to respond. -### Session +- Connection closed when state was authentication + This error happens when either the database doesn’t exist or if the user doesn't have the right credentials. -When a new client connects, a connection is assigned to the client until it disconnects. Afterward, the connection is returned back to the pool. +- Subscribe error: \{:error, :worker_not_found} + This log event is emitted when the client tries to connect to the database, but Supavisor does not have the necessary information to route the connection. Try reconnecting to the database as it can take some time for the project information to propagate to Supavisor. -All Postgres features can be used with this option. +- Subscribe error: \{:error, \{:badrpc, \{:error, \{:erpc, :timeout}}}} + This is a timeout error when the communication between different Supavisor nodes takes longer than expected. Try reconnecting to the database. -### Transaction - -This is the suggested option for serverless functions. A connection is assigned to the client for the duration of a transaction. Two consecutive transactions from the same client could be executed over two different connections. Some session-based Postgres features such as prepared statements are not available with this option. - -### Statement - -This is the most granular option. Connections are returned to the pool after every statement. Transactions with multiple statements are not allowed. This is best used when `AUTOCOMMIT` is in use. - -### Supavisor vs PgBouncer - -Supabase previously used PgBouncer for connection pooling. We have now deprecated PgBouncer in favor of Supavisor. Supavisor is available on all new and existing projects. - -[Supavisor](https://github.com/supabase/supavisor) is a new connection pooler by Supabase that runs on a high-availability cluster, segregated from your database. This means more resources are available for your database. No Application changes are required to switch from PgBouncer to Supavisor, you simply need to choose the new connection string from the "Connection Pooling" section on [Database settings](https://supabase.com/dashboard/project/_/settings/database). - -PgBouncer is now deprecated and is in the process of being removed from the platform, you can [see full details and timelines of the deprecation on Github Discussions](https://github.com/orgs/supabase/discussions/17817). Additionally, your Supabase database domain (db.projectref.supabase.co) will start resolving to an IPv6 address. No changes are required if your network supports IPv6. Otherwise, update your applications to use Supavisor which will continue to support IPv4 connections. - -[Read the full pgBouncer and IPv4 deprecation details](https://github.com/orgs/supabase/discussions/17817). +- Terminating with reason :client_termination when state was :busy + This error happens when the client terminates the connection before the connection with the database is completed. export const Page = ({ children }) => diff --git a/apps/docs/pages/guides/database/extensions/index_advisor.mdx b/apps/docs/pages/guides/database/extensions/index_advisor.mdx index 282e429e131..2330ea15892 100644 --- a/apps/docs/pages/guides/database/extensions/index_advisor.mdx +++ b/apps/docs/pages/guides/database/extensions/index_advisor.mdx @@ -6,7 +6,7 @@ export const meta = { description: 'Automatically optimize SQL queries', } -[Index advisor](https://github.com/supabase/index_advisor) is a Postgres extension for recommending indexes to improve query performance. +[Index advisor](https://database.dev/olirice/index_advisor) is a Postgres extension for recommending indexes to improve query performance. For example: @@ -154,7 +154,8 @@ from ## Resources -- Official [`index_advisor` GitHub Repository](https://github.com/supabase/index_advisor) +- dbdev [`index_advisor`](https://database.dev/olirice/index_advisor) docs +- dbdev [Github Repository](https://github.com/supabase/dbdev) export const Page = ({ children }) => diff --git a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx index 7cc9a02f4dd..30e18a67355 100644 --- a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx +++ b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx @@ -88,7 +88,6 @@ create table contacts ( id uuid default uuid_generate_v4(), first_name text, last_name text, - primary key (id) ); ``` diff --git a/apps/docs/pages/guides/database/managing-passwords.mdx b/apps/docs/pages/guides/database/managing-passwords.mdx index 4fc8c3a8b36..52bda4776ae 100644 --- a/apps/docs/pages/guides/database/managing-passwords.mdx +++ b/apps/docs/pages/guides/database/managing-passwords.mdx @@ -8,7 +8,7 @@ export const meta = { Your Postgres database is the core of your Supabase project, so it's important that it has a strong, secure password at all times. -If you use special symbols in your postgres password, you must remember to [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) your password later if using the postgres connection string e.g. `postgresql://postgres:p%3Dword@db.cvwawazfelidkloqmbma.supabase.co:5432/postgres` +If you use special symbols in your postgres password, you must remember to [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) your password later if using the postgres connection string e.g. `postgresql://postgres.projectref:p%3Dword@aws-0-us-east-1.pooler.supabase.com:6543/postgres` ## Changing your project password diff --git a/apps/docs/pages/guides/database/partitions.mdx b/apps/docs/pages/guides/database/partitions.mdx index e3c7df72de2..f109f8a6b97 100644 --- a/apps/docs/pages/guides/database/partitions.mdx +++ b/apps/docs/pages/guides/database/partitions.mdx @@ -157,7 +157,7 @@ partition by list(country); create table customers_americas partition of customers - for values in ('US', 'CANADA') + for values in ('US', 'CANADA'); create table customers_asia partition of customers diff --git a/apps/docs/pages/guides/database/postgres/roles.mdx b/apps/docs/pages/guides/database/postgres/roles.mdx index 1d3b785205a..a04ce85a9cc 100644 --- a/apps/docs/pages/guides/database/postgres/roles.mdx +++ b/apps/docs/pages/guides/database/postgres/roles.mdx @@ -40,7 +40,7 @@ Your Postgres database is the core of your Supabase project, so it's important t ### Special symbols in passwords -If you use special symbols in your Postgres password, you must remember to [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) your password later if using the Postgres connection string e.g. `postgresql://postgres:p%3Dword@db.xxx.supabase.co:5432/postgres`. +If you use special symbols in your postgres password, you must remember to [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) your password later if using the postgres connection string e.g. `postgresql://postgres.projectref:p%3Dword@aws-0-us-east-1.pooler.supabase.com:6543/postgres` ### Changing your project password diff --git a/apps/docs/pages/guides/database/postgres/triggers.mdx b/apps/docs/pages/guides/database/postgres/triggers.mdx index ff102f06153..81b2e67d74c 100644 --- a/apps/docs/pages/guides/database/postgres/triggers.mdx +++ b/apps/docs/pages/guides/database/postgres/triggers.mdx @@ -13,7 +13,7 @@ In Postgres, a trigger executes a set of actions automatically on table events s Creating triggers involve 2 parts: -1. A [Function](docs/guides/database/functions) which will be executed (called the Trigger Function) +1. A [Function](/docs/guides/database/functions) which will be executed (called the Trigger Function) 2. The actual Trigger object, with parameters around when the trigger should be run. An example of a trigger is: @@ -27,7 +27,7 @@ execute function trigger_function(); ## Trigger functions -A trigger function is a user-defined [Function](docs/guides/database/functions) that Postgres executes when the trigger is fired. +A trigger function is a user-defined [Function](/docs/guides/database/functions) that Postgres executes when the trigger is fired. ### Example trigger function diff --git a/apps/docs/pages/guides/database/sql-to-api.mdx b/apps/docs/pages/guides/database/sql-to-api.mdx index fa031db611b..9e8a486d0ae 100644 --- a/apps/docs/pages/guides/database/sql-to-api.mdx +++ b/apps/docs/pages/guides/database/sql-to-api.mdx @@ -13,7 +13,7 @@ Select a set of columns from a single table with where, order by, and limit clau ```sql select first_name, last_name, team_id, age from players -where age between 20 and 24 and team_id <> 'STL' +where age between 20 and 24 and team_id != 'STL' order by last_name, first_name desc limit 20; ``` @@ -52,7 +52,7 @@ Select all columns from a single table with a complex where clause: AND OR AND ```sql select * from players -where ((team_id = 'CHN' and age > 35) or (team_id <> 'CHN' and age is not null)); +where ((team_id = 'CHN' and age > 35) or (team_id != 'CHN' and age is not null)); ``` ```js diff --git a/apps/docs/pages/guides/functions/deploy.mdx b/apps/docs/pages/guides/functions/deploy.mdx index e285c74f8e9..838d3b0ed5d 100644 --- a/apps/docs/pages/guides/functions/deploy.mdx +++ b/apps/docs/pages/guides/functions/deploy.mdx @@ -5,7 +5,7 @@ export const meta = { title: 'Deploy to Production', description: 'Deploy your Edge Functions to your remote Supabase Project.', subtitle: 'Deploy your Edge Functions to your remote Supabase Project.', - tocVideo: 'rzglqRdZUQE', + tocVideo: '5OWH9c4u68M', } Once you have developed your Edge Functions locally, you can deploy them to your Supabase project. diff --git a/apps/docs/pages/guides/functions/local-development.mdx b/apps/docs/pages/guides/functions/local-development.mdx index 9a7ad164646..6fd6ca4b885 100644 --- a/apps/docs/pages/guides/functions/local-development.mdx +++ b/apps/docs/pages/guides/functions/local-development.mdx @@ -17,6 +17,12 @@ You can follow the [Deno guide](https://deno.com/manual@v1.32.5/getting_started/ When using VSCode, you should install both the Deno CLI and the the Deno language server [via this link](vscode:extension/denoland.vscode-deno) or by browsing the extensions in vscode and choosing to install the _Deno_ extension. + + +The Supabase CLI can automatically create helpful Deno settings when running `supabase init`. Simply select `y` when prompted "Generate VS Code settings for Deno? [y/N]"! + + + ## Deno support in subfolders You can enable the Deno language server for specific sub-paths in a workspace, while using VSCode's built-in JavaScript/TypeScript language server for all other files. @@ -41,7 +47,7 @@ To enable the Deno language server only for the `supabase/functions` folder, add ## Multi-root workspaces in VSCode -When developing with VS Code inside of an existing application, you can utilize [multi-root workspaces](https://code.visualstudio.com/docs/editor/workspaces#_multiroot-workspaces). +We recommend using `deno.enablePaths` mentioned above as it's easier to manage, however if you like [multi-root workspaces](https://code.visualstudio.com/docs/editor/workspaces#_multiroot-workspaces) you can use these as an alternative.
-Can't wait to get started? Develop, test, and deploy your first Supabase Edge Function in less than 7 minutes with our [Quickstart Video Tutorial](https://youtu.be/rzglqRdZUQE)! +Can't wait to get started? Develop, test, and deploy your first Supabase Edge Function in less than 7 minutes with our [Quickstart Video Tutorial](https://youtu.be/5OWH9c4u68M)! Check the [Edge Functions Docs](https://supabase.com/docs/guides/functions) for the steps. ## Example apps: Mobile payments with React Native and Flutter diff --git a/apps/www/_blog/2022-04-01-hackathon-bring-the-func.mdx b/apps/www/_blog/2022-04-01-hackathon-bring-the-func.mdx index bc1d8912cf2..eb56c546e71 100644 --- a/apps/www/_blog/2022-04-01-hackathon-bring-the-func.mdx +++ b/apps/www/_blog/2022-04-01-hackathon-bring-the-func.mdx @@ -130,7 +130,7 @@ Here's a collection of resources that will help you get started building with Su - Getting started with [GraphQL on Supabase](https://supabase.com/blog/graphql-now-available#getting-started) - [GraphQL HackerNews clone](https://supabase-graphql-example.vercel.app/) - [Edge Functions Guide](https://supabase.com/docs/guides/functions) -- [Edge Functions Quickstart video](https://youtu.be/rzglqRdZUQE) +- [Edge Functions Quickstart video](https://youtu.be/5OWH9c4u68M) - [Supabase CLI local development guide](https://supabase.com/docs/guides/local-development) - [Edge Functions examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) diff --git a/apps/www/_blog/2022-04-18-bring-the-func-hackathon-winners.mdx b/apps/www/_blog/2022-04-18-bring-the-func-hackathon-winners.mdx index de6ded9d33e..a4f41165054 100644 --- a/apps/www/_blog/2022-04-18-bring-the-func-hackathon-winners.mdx +++ b/apps/www/_blog/2022-04-18-bring-the-func-hackathon-winners.mdx @@ -99,7 +99,7 @@ If you're inspired to build, check out some of the latest resources: - Getting started with [GraphQL on Supabase](https://supabase.com/blog/graphql-now-available#getting-started) - [GraphQL HackerNews clone](https://supabase-graphql-example.vercel.app/) - [Edge Functions Guide](https://supabase.com/docs/guides/functions) -- [Edge Functions Quickstart video](https://youtu.be/rzglqRdZUQE) +- [Edge Functions Quickstart video](https://youtu.be/5OWH9c4u68M) - [Supabase CLI local development guide](https://supabase.com/docs/guides/local-development) - [Edge Functions examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) diff --git a/apps/www/_blog/2022-08-24-building-a-realtime-trello-board-with-supabase-and-angular.mdx b/apps/www/_blog/2022-08-24-building-a-realtime-trello-board-with-supabase-and-angular.mdx index d5a1f64196e..cd6380cef06 100644 --- a/apps/www/_blog/2022-08-24-building-a-realtime-trello-board-with-supabase-and-angular.mdx +++ b/apps/www/_blog/2022-08-24-building-a-realtime-trello-board-with-supabase-and-angular.mdx @@ -614,7 +614,10 @@ import { filter, map, take } from 'rxjs/operators' providedIn: 'root', }) export class AuthGuard implements CanActivate { - constructor(private auth: AuthService, private router: Router) {} + constructor( + private auth: AuthService, + private router: Router + ) {} canActivate(): Observable { return this.auth.currentUser.pipe( diff --git a/apps/www/_blog/2022-11-08-authentication-in-ionic-angular.mdx b/apps/www/_blog/2022-11-08-authentication-in-ionic-angular.mdx index e34c4d02fa7..d4440080197 100644 --- a/apps/www/_blog/2022-11-08-authentication-in-ionic-angular.mdx +++ b/apps/www/_blog/2022-11-08-authentication-in-ionic-angular.mdx @@ -1479,7 +1479,11 @@ import { App, URLOpenListenerEvent } from '@capacitor/app' styleUrls: ['app.component.scss'], }) export class AppComponent { - constructor(private zone: NgZone, private router: Router, private authService: AuthService) { + constructor( + private zone: NgZone, + private router: Router, + private authService: AuthService + ) { this.setupListener() } diff --git a/apps/www/_blog/2023-03-01-geo-queries-with-postgis-in-ionic-angular.mdx b/apps/www/_blog/2023-03-01-geo-queries-with-postgis-in-ionic-angular.mdx index 2213babdbf0..f8b6a3b7900 100644 --- a/apps/www/_blog/2023-03-01-geo-queries-with-postgis-in-ionic-angular.mdx +++ b/apps/www/_blog/2023-03-01-geo-queries-with-postgis-in-ionic-angular.mdx @@ -501,7 +501,10 @@ export class StorePage implements OnInit { long: undefined, } - constructor(public modalCtrl: ModalController, private storesService: StoresService) {} + constructor( + public modalCtrl: ModalController, + private storesService: StoresService + ) {} ngOnInit() {} @@ -629,7 +632,10 @@ export class HomePage { selectedMarker: StoreMarker | null = null selectedStore: StoreResult | null = null - constructor(private storesService: StoresService, private modalCtrl: ModalController) {} + constructor( + private storesService: StoresService, + private modalCtrl: ModalController + ) {} ionViewDidEnter() { this.createMap() diff --git a/apps/www/_blog/2023-10-03-postgres-dynamic-table-partitioning.mdx b/apps/www/_blog/2023-10-03-postgres-dynamic-table-partitioning.mdx index a757bb9c220..922254a3ca1 100644 --- a/apps/www/_blog/2023-10-03-postgres-dynamic-table-partitioning.mdx +++ b/apps/www/_blog/2023-10-03-postgres-dynamic-table-partitioning.mdx @@ -38,20 +38,20 @@ Partitioning is a simple solution, but for Postgres this usually requires settin Let’s explore a working example showing how to escape this situation using dynamic table partitioning. We’ll setup a simulated “chat app” that has to store possibly millions of chat messages per day. The first step is to set up a fake “Large Table” problem to simulate a data set that has grown past where Postgres can handle it all in one table. So first, we’ll add a couple of new tables for our example chat app: ```sql -CREATE TABLE chats( +create table chats ( id bigserial, - created_at timestamptz NOT NULL DEFAULT now(), - PRIMARY KEY (id) + created_at timestamptz not null default now(), + primary key (id) ); -CREATE TABLE chat_messages( +create table chat_messages ( id bigserial, - created_at timestamptz NOT NULL, - chat_id bigint NOT NULL, - chat_created_at timestamptz NOT NULL, - message text NOT NULL, - PRIMARY KEY (id), - FOREIGN KEY (chat_id) REFERENCES chats(id) + created_at timestamptz not null, + chat_id bigint not null, + chat_created_at timestamptz not null, + message text not null, + primary key (id), + foreign key (chat_id) references chats (id) ); ``` diff --git a/apps/www/_blog/2024-01-17-what-is-saml-authentication.mdx b/apps/www/_blog/2024-01-17-what-is-saml-authentication.mdx index aa911c9b5e4..2fd73b52598 100644 --- a/apps/www/_blog/2024-01-17-what-is-saml-authentication.mdx +++ b/apps/www/_blog/2024-01-17-what-is-saml-authentication.mdx @@ -130,7 +130,7 @@ create table invited_users ( We can create an RLS policy to enforce that a developer in ACME Inc. can only invite someone who is also a developer in the same company: ```sql -create policy "View " +create policy "Can only invite developers in the same organization" on invited_users as restrictive for insert diff --git a/apps/www/_blog/2024-01-22-laravel-postgres.mdx b/apps/www/_blog/2024-01-22-laravel-postgres.mdx index 1a1a78fe677..a677113a1fa 100644 --- a/apps/www/_blog/2024-01-22-laravel-postgres.mdx +++ b/apps/www/_blog/2024-01-22-laravel-postgres.mdx @@ -71,7 +71,7 @@ Laravel ships with a Postgres adapter out of the box, you can simply configure i ```bash .env DB_CONNECTION=pgsql -DATABASE_URL=postgres://postgres.xxxx:password@xxxx.pooler.supabase.com:6543/postgres +DATABASE_URL=postgres://postgres.xxxx:password@xxxx.pooler.supabase.com:5432/postgres ``` ### Change the default schema diff --git a/apps/www/_blog/2024-01-24-how-pg-graphql-works.mdx b/apps/www/_blog/2024-01-24-how-pg-graphql-works.mdx index c58840cbea7..cdfd1cb98f0 100644 --- a/apps/www/_blog/2024-01-24-how-pg-graphql-works.mdx +++ b/apps/www/_blog/2024-01-24-how-pg-graphql-works.mdx @@ -9,6 +9,7 @@ categories: tags: - pg-graphql - supabase-engineering + - planetpg date: '2024-01-24' toc_depth: 3 --- diff --git a/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx b/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx index b95b02f8b9c..8640a76f8c2 100644 --- a/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx +++ b/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx @@ -2,8 +2,8 @@ title: Create a Figma Clone app with Flutter and Supabase Realtime description: 'A tutorial on how to build a collaborative design app like Figma using Flutter and Supabase Realtime.' author: tyler_shukert -image: flutter-figma-clone/og.png -thumb: flutter-figma-clone/thumb.png +image: flutter-figma-clone/figma-clone-og.jpg +thumb: flutter-figma-clone/figma-clone-og.jpg categories: - developers tags: @@ -35,8 +35,6 @@ We are building an interactive design canvas app where multiple users can collab /> -https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/videos/marketing/blog/flutter-figma-clone/flutter-figma-clone.mp4 - Okay, Figma clone might be an overstatement. However, the point of this article is to demonstrate how to build a collaborative app with all the fundamental elements of a collaborative design canvas. You can take the concepts of this app, add features, refine it, and make it as sophisticated as Figma. ## Setting up the app @@ -859,3 +857,9 @@ At this point, we have implemented everything we need to create a collaborative In this article, we learned how we can combine the [Supabase Realtime Broadcast](https://supabase.com/docs/guides/realtime/broadcast) feature with Flutter’s `CustomPainter` to create a collaborative design app. We learned how to implement real-time communication between multiple clients using the Broadcast feature, and how we can broadcast the shape and cursor data to other connected clients in real-time. This article only used circles and rectangles to keep things simple, but you can easily add support for other types of objects like texts or arrows just by extending the `CanvasObject` class to make the app more like Figma. Another fun way to expand this app would be to add authentication using [Supabase Auth](https://supabase.com/docs/guides/auth) so that we can add proper authorizations. Adding an image upload feature using [Supabase Storage](https://supabase.com/docs/guides/storage) would certainly open up more creative options for the app. + +## Resources + +- [Create live cursor app with Flutter and Supabase video](https://www.youtube.com/watch?v=QhRNXlFLaeE) +- [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game) +- [Getting started with Flutter authentication](https://supabase.com/blog/flutter-authentication) diff --git a/apps/www/_blog/2024-01-29-ruby-on-rails-postgres.mdx b/apps/www/_blog/2024-01-29-ruby-on-rails-postgres.mdx new file mode 100644 index 00000000000..25214352417 --- /dev/null +++ b/apps/www/_blog/2024-01-29-ruby-on-rails-postgres.mdx @@ -0,0 +1,155 @@ +--- +title: Getting started with Ruby on Rails and Postgres on Supabase +description: 'Learn how to create a new Rails app and connect it to a Supabase Postgres database.' +author: thor_schaeff +image: getting-started/rails/rails.jpg +thumb: getting-started/rails/rails.jpg +categories: + - engineering +tags: + - postgres + - developers + - ruby +date: '2024-01-29' +toc_depth: 3 +--- + +Every Supabase project comes with a full [Postgres](https://www.postgresql.org/) database, a free and open source database which is considered one of the world's most stable and advanced databases. + +Postgres is an ideal choice for your Ruby on Rails applications as Rails ships with a built-in Postgres adapter! + +In this post we'll start from scratch, creating a new Rails project, connecting it to our Supabase Postgres database, and interacting with the database using the Rails Console. + + + +Supabase is one of the best [free alternatives to Heroku Postgres](/alternatives/supabase-vs-heroku-postgres). See [this guide](/docs/guides/resources/migrating-to-supabase/heroku) to learn how to migrate from Heroku to Supabase. + +There's also a [Heroku to Supabase migration tool](https://migrate.supabase.com/) available to migrate in just a few clicks. + + + +If you prefer video guide, you can follow along below. And make sure to subscribe to the [Supabase YouTube channel](https://www.youtube.com/channel/UCNTVzV1InxHV-YR0fSajqPQ?view_as=subscriber&sub_confirmation=1)! + +
+