diff --git a/apps/docs/components/DocSearch.tsx b/apps/docs/components/DocSearch.tsx index d8bde374580..2a4f56d1e48 100644 --- a/apps/docs/components/DocSearch.tsx +++ b/apps/docs/components/DocSearch.tsx @@ -20,7 +20,6 @@ export function SearchProvider({ children }: any) { const router = useRouter() const [isOpen, setIsOpen] = useState(false) const [initialQuery, setInitialQuery] = useState(null) - const onOpen = useCallback(() => { setIsOpen(true) }, [setIsOpen]) @@ -85,6 +84,7 @@ export function SearchProvider({ children }: any) { hitComponent={Hit} transformItems={(items) => { return items.map((item, index) => { + console.log('item', item) // We transform the absolute URL into a relative URL to // leverage Next's preloading. const a = document.createElement('a') @@ -96,7 +96,8 @@ export function SearchProvider({ children }: any) { ...item, url: `${a.pathname}${hash}`, __is_result: () => true, - __is_parent: () => item.type === 'lvl1' && items.length > 1 && index === 0, + __is_parent: () => item.type === 'lvl1' && index === 0, + __is_guide: () => item.hierarchy.lvl0 === 'Guides', __is_child: () => item.type !== 'lvl1' && items.length > 1 && @@ -125,6 +126,7 @@ function Hit({ hit, children }) { 'DocSearch-Hit--FirstChild': hit.__is_first?.(), 'DocSearch-Hit--LastChild': hit.__is_last?.(), 'DocSearch-Hit--Child': hit.__is_child?.(), + 'DocSearch-Hit--Guide': hit.__is_guide?.(), })} > {children} diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index e686c28dd60..6a210a4cf67 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -298,6 +298,7 @@ export const auth = { url: '/guides/auth/social-login', items: [...SocialLoginItems], }, + { name: 'Email Templates', url: '/guides/auth/auth-email-templates', items: [] }, ], }, { @@ -468,6 +469,7 @@ export const platform = { items: [ { name: 'Compute Add-ons', url: '/guides/platform/compute-add-ons', items: [] }, { name: 'Custom Domains', url: '/guides/platform/custom-domains', items: [] }, + { name: 'Database Backups', url: '/guides/platform/backups', items: [] }, ], }, { @@ -674,6 +676,11 @@ export const integrations = { { name: 'Plasmic', url: '/guides/integrations/plasmic', items: [] }, ], }, + { + name: 'Messaging', + url: undefined, + items: [{ name: 'OneSignal', url: '/guides/integrations/onesignal', items: [] }], + }, ], } diff --git a/apps/docs/components/index.tsx b/apps/docs/components/index.tsx index 4351050cbf0..c5a5aa3752a 100644 --- a/apps/docs/components/index.tsx +++ b/apps/docs/components/index.tsx @@ -27,6 +27,9 @@ import RefHeaderSection from './reference/RefHeaderSection' // Ref version specific import CliGlobalFlagsHandler from '~/components/reference/enrichments/cli/CliGlobalFlagsHandler' +import Options from '~/components/Options' +import Param from '~/components/Params' + const components = { Admonition, Button, @@ -68,6 +71,8 @@ const components = { code: (props: any) => , RefHeaderSection: (props: any) => , CliGlobalFlagsHandler: () => , + Options, + Param, } export default components diff --git a/apps/docs/components/reference/CLICommandSection.tsx b/apps/docs/components/reference/CLICommandSection.tsx index 89cae3bfb24..9f685157482 100644 --- a/apps/docs/components/reference/CLICommandSection.tsx +++ b/apps/docs/components/reference/CLICommandSection.tsx @@ -27,6 +27,7 @@ export type Flag = { description: string default_value: string accepted_values: AcceptedValue[] + required?: boolean } export type AcceptedValue = { @@ -107,7 +108,7 @@ const CliCommandSection = (props) => { {command.flags.map((flag: Flag) => ( <>
  • - + {flag?.accepted_values && ( {flag?.accepted_values.map((value) => { diff --git a/apps/docs/data/authProviders.ts b/apps/docs/data/authProviders.ts index f9a32a71454..95c2f6b2dbf 100644 --- a/apps/docs/data/authProviders.ts +++ b/apps/docs/data/authProviders.ts @@ -1,26 +1,8 @@ const authProviders = [ - // { - // name: 'Email', - // // logo: '/img/libraries/dart-icon.svg', - // href: '/docs/guides/auth/auth-apple', - // official: true, - // supporter: 'Supabase', - // platform: true, - // selfHosted: true, - // }, - // { - // name: 'Magic Links', - // // logo: '/img/libraries/dart-icon.svg', - // href: '/docs/guides/auth/auth-apple', - // official: true, - // supporter: 'Supabase', - // platform: true, - // selfHosted: true, - // }, { name: 'Apple', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-apple', + href: '/guides/auth/social-login/auth-apple', official: true, supporter: 'Supabase', platform: true, @@ -29,7 +11,7 @@ const authProviders = [ { name: 'Azure', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-azure', + href: '/guides/auth/social-login/auth-azure', official: false, supporter: 'TBD', platform: true, @@ -38,7 +20,7 @@ const authProviders = [ { name: 'Bitbucket', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-bitbucket', + href: '/guides/auth/social-login/auth-bitbucket', official: true, supporter: 'Supabase', platform: true, @@ -47,7 +29,7 @@ const authProviders = [ { name: 'Discord', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-discord', + href: '/guides/auth/social-login/auth-discord', official: true, supporter: 'Supabase', platform: true, @@ -56,7 +38,7 @@ const authProviders = [ { name: 'Facebook', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-facebook', + href: '/guides/auth/social-login/auth-facebook', official: true, supporter: 'Supabase', platform: true, @@ -65,7 +47,7 @@ const authProviders = [ { name: 'GitHub', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-github', + href: '/guides/auth/social-login/auth-github', official: true, supporter: 'Supabase', platform: true, @@ -74,7 +56,7 @@ const authProviders = [ { name: 'GitLab', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-gitlab', + href: '/guides/auth/social-login/auth-gitlab', official: true, supporter: 'Supabase', platform: true, @@ -83,7 +65,7 @@ const authProviders = [ { name: 'Google', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-google', + href: '/guides/auth/social-login/auth-google', official: true, supporter: 'Supabase', platform: true, @@ -91,7 +73,7 @@ const authProviders = [ }, { name: 'Keycloak', - href: '/guides/auth/auth-keycloak', + href: '/guides/auth/social-login/auth-keycloak', official: true, supporter: 'Supabase', platform: true, @@ -100,7 +82,7 @@ const authProviders = [ { name: 'LinkedIn', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-linkedin', + href: '/guides/auth/social-login/auth-linkedin', official: true, supporter: 'Supabase', platform: true, @@ -109,7 +91,7 @@ const authProviders = [ { name: 'MessageBird', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-messagebird', + href: '/guides/auth/phone-login/messagebird', official: false, supporter: 'MessageBird', platform: true, @@ -118,7 +100,7 @@ const authProviders = [ { name: 'Notion', // logo: '/img/libraries/notion-icon.svg', - href: '/guides/auth/auth-notion', + href: '/guides/auth/social-login/auth-notion', official: true, supporter: 'Supabase', platform: true, @@ -127,7 +109,7 @@ const authProviders = [ { name: 'Slack', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-slack', + href: '/guides/auth/social-login/auth-slack', official: true, supporter: 'Supabase', platform: true, @@ -136,7 +118,7 @@ const authProviders = [ { name: 'Spotify', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-spotify', + href: '/guides/auth/social-login/auth-spotify', official: true, supporter: 'Supabase', platform: true, @@ -145,7 +127,7 @@ const authProviders = [ { name: 'Twitter', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-twitter', + href: '/guides/auth/social-login/auth-twitter', official: true, supporter: 'Supabase', platform: true, @@ -154,7 +136,7 @@ const authProviders = [ { name: 'Twitch', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-twitch', + href: '/guides/auth/social-login/auth-twitch', official: true, supporter: 'Supabase', platform: true, @@ -163,7 +145,7 @@ const authProviders = [ { name: 'Zoom', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-zoom', + href: '/guides/auth/social-login/auth-zoom', official: true, supporter: 'Supabase', platform: true, @@ -172,7 +154,7 @@ const authProviders = [ { name: 'Twilio', // logo: '/img/libraries/dart-icon.svg', - href: '/guides/auth/auth-twilio', + href: '/guides/auth/phone-login/twilio', official: true, supporter: 'Supabase', platform: true, @@ -180,7 +162,7 @@ const authProviders = [ }, { name: 'Vonage', - href: '/guides/auth/auth-vonage', + href: '/guides/auth/phone-login/vonage', official: false, supporter: 'Supabase', platform: true, diff --git a/apps/docs/internals/files/api.mjs b/apps/docs/internals/files/api.mjs new file mode 100644 index 00000000000..0f405c4edf2 --- /dev/null +++ b/apps/docs/internals/files/api.mjs @@ -0,0 +1,13 @@ +import sections from '../../../../spec/common-api-sections.json' assert { type: 'json' } +import { flattenSections } from '../helpers.mjs' + +const flatSections = flattenSections(sections) + +export function generateAPIPages() { + let apiPages = [] + + flatSections.map((section) => { + apiPages.push(`reference/api/${section.slug}`) + }) + return apiPages +} diff --git a/apps/docs/internals/files/cli.mjs b/apps/docs/internals/files/cli.mjs new file mode 100644 index 00000000000..9b7dad46168 --- /dev/null +++ b/apps/docs/internals/files/cli.mjs @@ -0,0 +1,18 @@ +import fs from 'fs' +import yaml from 'js-yaml' +import cliCommonSections from '../../../../spec/common-cli-sections.json' assert { type: 'json' } +import { flattenSections } from '../helpers.mjs' + +const flatCLISections = flattenSections(cliCommonSections) + +const cliSpec = yaml.load(fs.readFileSync(`../../spec/cli_v1_commands.yaml`, 'utf8')) + +export function generateCLIPages() { + let cliPages = [] + + cliSpec.commands.map((section) => { + const slug = flatCLISections.find((item) => item.id === section.id)?.slug + if (slug) cliPages.push(`reference/cli/${slug}`) + }) + return cliPages +} diff --git a/apps/docs/internals/files/reference-lib.mjs b/apps/docs/internals/files/reference-lib.mjs new file mode 100644 index 00000000000..ee95d4ee625 --- /dev/null +++ b/apps/docs/internals/files/reference-lib.mjs @@ -0,0 +1,27 @@ +import fs from 'fs' + +import yaml from 'js-yaml' +import commonLibSections from '../../../../spec/common-client-libs-sections.json' assert { type: 'json' } +import { flattenSections } from '../helpers.mjs' + +const flatCommonLibSections = flattenSections(commonLibSections) + +const clientLibFiles = [ + { fileName: 'supabase_js_v2', label: 'javascript', version: 'v2', versionSlug: false }, + { fileName: 'supabase_js_v1', label: 'javascript', version: 'v1', versionSlug: true }, + { fileName: 'supabase_dart_v1', label: 'dart', version: 'v1', versionSlug: false }, + { fileName: 'supabase_dart_v0', label: 'dart', version: 'v0', versionSlug: true }, + { fileName: 'supabase_dart_v0', label: 'dart', version: 'v0', versionSlug: true }, +] + +export function generateReferencePages() { + let refPages = [] + clientLibFiles.map((file) => { + const spec = yaml.load(fs.readFileSync(`../../spec/${file.fileName}.yml`, 'utf8')) + spec.functions.map((fn) => { + const slug = flatCommonLibSections.find((item) => item.id === fn.id)?.slug + refPages.push(`reference/${file.label}/${file.versionSlug ? file.version + '/' : ''}${slug}`) + }) + }) + return refPages +} diff --git a/apps/docs/internals/generate-sitemap.mjs b/apps/docs/internals/generate-sitemap.mjs index 2260e0aebf9..52c00e86bbc 100644 --- a/apps/docs/internals/generate-sitemap.mjs +++ b/apps/docs/internals/generate-sitemap.mjs @@ -1,65 +1,49 @@ -import { writeFileSync } from 'fs' -import { globby } from 'globby' -import prettier from 'prettier' - /* * kudos to leerob from vercel * https://leerob.io/blog/nextjs-sitemap-robots */ +import { writeFileSync } from 'fs' +import { globby } from 'globby' +import prettier from 'prettier' +import { generateCLIPages } from './files/cli.mjs' +import { generateReferencePages } from './files/reference-lib.mjs' +import { generateAPIPages } from './files/api.mjs' + +const referencePages = generateReferencePages() +const cliPages = generateCLIPages() +const apiPages = generateAPIPages() + async function generate() { const prettierConfig = await prettier.resolveConfig('./.prettierrc.js') const rawPages = await globby([ // guides 'docs/*.mdx', - '!docs/404.mdx', 'pages/**/*.mdx', - // reference - 'docs/reference/*.mdx', - 'docs/reference/javascript/*.mdx', - 'docs/reference/javascript/generated/*.mdx', - '!docs/reference/javascript/v1.mdx', // ignore this - 'docs/reference/dart/*.mdx', - 'docs/reference/dart/generated/*.mdx', - '!docs/reference/dart/v0.mdx', // ignore this - 'docs/reference/api/*.mdx', - 'docs/reference/api/generated/*.mdx', - 'docs/reference/cli/*.mdx', - 'docs/reference/cli/generated/*.mdx', - // misc reference - 'docs/reference/postgres/*.mdx', - 'docs/reference/postgres/generated/*.mdx', - 'docs/reference/realtime/*.mdx', - 'docs/reference/realtime/generated/*.mdx', - 'docs/reference/storage/*.mdx', - 'docs/reference/storage/generated/*.mdx', - 'docs/reference/auth/*.mdx', - 'docs/reference/auth/generated/*.mdx', + '!pages/404.mdx', + '!pages/404.tsx', + '!pages/ref-pages.mdx', ]) - const pages = rawPages.map((x) => { + const guidePages = rawPages.map((x) => { let string = x - string = string.replace('/generated', '') + string = string.replace('pages/', '') string = string.replace('.mdx', '') return string }) - // add static OSS page - pages.unshift('docs/oss') - // add static homepage - pages.unshift('docs') + // combine the guidePages with the ref pages + const allPages = guidePages.concat(referencePages, cliPages, apiPages) const sitemap = ` - ${pages + ${allPages .map((path) => { - // fix homepage - path = path.replace('pages/index', '') return ` - ${`https://supabase.com/${path.replace('pages/', 'docs/')}`} + ${`https://supabase.com/docs/${path}`} weekly 0.5 @@ -75,7 +59,9 @@ async function generate() { }) const sitemapFilePath = `public/sitemap.xml` - console.log(`Total of ${pages.length} pages in sitemap, located at /apps/docs/${sitemapFilePath}`) + console.log( + `Total of ${allPages.length} pages in sitemap, located at /apps/docs/${sitemapFilePath}` + ) // eslint-disable-next-line no-sync writeFileSync(sitemapFilePath, formatted) diff --git a/apps/docs/internals/helpers.mjs b/apps/docs/internals/helpers.mjs new file mode 100644 index 00000000000..afb833fee4d --- /dev/null +++ b/apps/docs/internals/helpers.mjs @@ -0,0 +1,15 @@ +export function flattenSections(sections) { + var a = [] + for (var i = 0; i < sections.length; i++) { + if (sections[i].id) { + // only push a section that has an id + // these are reserved for sidebar subtitles + a.push(sections[i]) + } + if (sections[i].items) { + // if there are subitems, loop through + a = a.concat(flattenSections(sections[i].items)) + } + } + return a +} diff --git a/apps/docs/internals/tsconfig.json b/apps/docs/internals/tsconfig.json new file mode 100644 index 00000000000..de1ecb67a32 --- /dev/null +++ b/apps/docs/internals/tsconfig.json @@ -0,0 +1,15 @@ +// generator files need their own tsconfig.json because they don't like "module": "esnext" setting that nextjs requires in the main tsconfig +{ + "compilerOptions": { + "incremental": true, + "noImplicitAny": false, + "esModuleInterop": true, + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "~/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/apps/docs/lib/refGenerator/helpers.ts b/apps/docs/lib/refGenerator/helpers.ts index ed8f18f5e4e..6af5b8eb539 100644 --- a/apps/docs/lib/refGenerator/helpers.ts +++ b/apps/docs/lib/refGenerator/helpers.ts @@ -1,4 +1,4 @@ -import { TsDoc } from '~/generator/legacy/definitions' +import { TsDoc } from '../../generator/legacy/definitions' import { values, mapValues } from 'lodash' import { OpenAPIV3 } from 'openapi-types' @@ -60,6 +60,8 @@ function recurseThroughParams(paramDefinition: any) { children = dereferenced.children } else if (dereferenced.type?.declaration?.children) { children = dereferenced.type.declaration.children + } else if (dereferenced.type?.type === 'query') { + // skip: ignore types created from `typeof` for now, like `type Fetch = typeof fetch` } else if (dereferenced.type?.type === 'union') { // skip: we don't want to show unions as nested parameters } else if (Object.keys(dereferenced).length === 0) { diff --git a/apps/docs/package.json b/apps/docs/package.json index 4c40db4e3d1..2abc71adb53 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -8,7 +8,7 @@ "start": "next start", "lint": "next lint", "build:sitemap": "node ./internals/generate-sitemap.mjs", - "postbuild": "node ./scripts/build-search.js && node ./internals/generate-sitemap.mjs", + "postbuild": "ts-node ./scripts/build-search.ts && node ./internals/generate-sitemap.mjs", "generate:all": "npm-run-all --parallel gen:api gen:cli gen:gotrue gen:storage gen:supabase-dart:v0 gen:supabase-dart:v1 gen:supabase-js:v1 gen:supabase-js:v2 gen:realtime", "gen:api": "npm-run-all gen:api:usage", "gen:api:usage": "ts-node ./generator/index.ts gen --type api --url https://api.supabase.com --input ../../spec/transforms/api_v0_openapi_deparsed.json --output ./docs/reference/api/generated/usage.mdx", diff --git a/apps/docs/pages/guides/auth/auth-email-templates.mdx b/apps/docs/pages/guides/auth/auth-email-templates.mdx new file mode 100644 index 00000000000..a82c244000b --- /dev/null +++ b/apps/docs/pages/guides/auth/auth-email-templates.mdx @@ -0,0 +1,50 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + title: 'Email Templates', + description: 'Learn how to configure the email templates on Supabase.', +} + +You can customize the email messages used for the authentication flows. You can edit the following email templates: + +- Confirm signup +- Invite user +- Magic Link +- Change Email Address +- Reset Password + +## Terminology + +The templating system provides the following variables for use: + +| Name | Description | +| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `{{ .ConfirmationURL }}` | Contains the confirmation URL. For example, a signup confirmation URL would look like: `https://project-ref.supabase.co/auth/v1/verify?token={{ .TokenHash }}&type=signup&redirect_to=https://example.com/path` . | +| `{{ .Token }}` | Contains a 6-digit One-Time-Password (OTP) that can be used instead of the `{{. ConfirmationURL }}` . | +| `{{ .TokenHash }}` | Contains a hashed version of the `{{ .Token }}`. This is useful for constructing your own email link in the email template. | +| `{{ .SiteURL }}` | Contains your application's Site URL. This can be configured in your project's [authentication settings](https://app.supabase.com/project/_/auth/url-configuration). | + +## Limitations + +### Email Prefetching + +Certain email providers may have spam detection or other security features that prefetch URL links from incoming emails. +In this scenario, the `{{ .ConfirmationURL }}` sent will be consumed instantly which leads to a "Token has expired or is invalid" error. +To guard against this: + +- Use an email OTP instead by including `{{ .Token }}` in the email template. +- Create your own custom email link to redirect the user to a page where they can click on a button to confirm the action. + For example, you can include the following in your email template: + + ```html + Confirm your signup + + ``` + + The user should be brought to a page on your site where they can confirm the action by clicking a button. + The button should contain the actual confirmation link which can be obtained from parsing the `confirmation_url={{ .ConfirmationURL }}` query parameter in the URL. + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs-server-components.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs-server-components.mdx index 346c8d7f3bc..10fa7f73f31 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs-server-components.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs-server-components.mdx @@ -95,7 +95,7 @@ Create a new file at `/utils/supabase-browser.ts` and populate with the followin ```ts import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { Database } from '../db_types' +import { Database } from '../lib/database.types' export default createBrowserSupabaseClient() ``` @@ -109,7 +109,7 @@ Create a new file at `/utils/supabase-server.ts` and populate with the following ```ts title="/utils/supabase-server.ts" import { headers, cookies } from 'next/headers' import { createServerComponentSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { Database } from '../db_types' +import { Database } from '../lib/database.types' export default () => createServerComponentSupabaseClient({ @@ -139,6 +139,8 @@ Middleware runs before every route declared in the `matcher` array. Since we don > +Create a new file at `/pages/middleware.js` and populate with the following: + ```jsx title="middleware.js" import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' @@ -164,6 +166,8 @@ export const config = { +Create a new file at `/middleware.ts` (a sibling of /pages) and populate with the following: + ```tsx title="middleware.ts" import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' @@ -254,7 +258,7 @@ export default async function RootLayout({ children }) { } ``` -We don't want Next.js to cache this `session` value, so we need to export a `revalidate` value of `0`. +We don't want Next.js to cache this `session` value, so we need to export a `revalidate` value of `0` in the layout file. ```jsx export const revalidate = 0 @@ -641,7 +645,7 @@ Create a new file at `/app/realtime/posts.tsx` and populate with the following: 'use client' import { useEffect, useState } from 'react' -import { Database } from '../../db_types' +import { Database } from '../lib/database.types' import supabase from '../../utils/supabase-browser' type Post = Database['public']['Tables']['posts']['Row'] diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index c38f8f3b284..d0e74b82999 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -162,6 +162,7 @@ const supabaseClient = useSupabaseClient() ```tsx // Creating a new supabase server client object (e.g. in API route): +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' import type { NextApiRequest, NextApiResponse } from 'next' import type { Database } from 'types_db' diff --git a/apps/docs/pages/guides/database/extensions/pgnet.mdx b/apps/docs/pages/guides/database/extensions/pgnet.mdx index f9b99c7e018..29283ab4430 100644 --- a/apps/docs/pages/guides/database/extensions/pgnet.mdx +++ b/apps/docs/pages/guides/database/extensions/pgnet.mdx @@ -36,11 +36,11 @@ It differs from the `http` extension in that it is asynchronous by default. This ```sql --- Example: enable the "pg_net" extension -create schema if not exists net; -create extension pg_net with schema net; +-- Example: enable the "pg_net" extension. +create extension pg_net; +-- Note: The extension creates its own schema/namespace named "net" to avoid naming conflicts. --- Example: disable the "plv8" extension +-- Example: disable the "pg_net" extension drop extension if exists pg_net; drop schema net; ``` diff --git a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx index 2731ae221a2..167e9b92807 100644 --- a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx +++ b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx @@ -10,8 +10,8 @@ The `uuid-ossp` extension can be used to generate a `UUID`. ## Overview -A `UUID` is a "Universally Unique Identifer" and it is, for practical purposes, unique. -This makes them particularly well suited as Primary Keys. It is occasionally referred to as a `GUID`, which stands for "Globally Unique Identifer". +A `UUID` is a "Universally Unique Identifier" and it is, for practical purposes, unique. +This makes them particularly well suited as Primary Keys. It is occasionally referred to as a `GUID`, which stands for "Globally Unique Identifier". ## Usage diff --git a/apps/docs/pages/guides/database/tables.mdx b/apps/docs/pages/guides/database/tables.mdx index 010b104a2a4..78d1b62115a 100644 --- a/apps/docs/pages/guides/database/tables.mdx +++ b/apps/docs/pages/guides/database/tables.mdx @@ -265,7 +265,7 @@ For example if you had the following situations: - You have a list of `movies`. - A movie can have several `actors`. -- An `actor` can perfom in several movies. +- An `actor` can perform in several movies. { + const [user, setUser] = useState(null) + + const [oneSignalInitialized, setOneSignalInitialized] = + useState(false) + + /** + * Initializes OneSignal SDK for a given Supabase User ID + * @param uid Supabase User ID + */ + const initializeOneSignal = async (uid: string) => { + if (oneSignalInitialized) { + return + } + setOneSignalInitialized(true) + await OneSignal.init({ + appId: oneSignalAppId, + notifyButton: { + enable: true, + }, + + allowLocalhostAsSecureOrigin: true, + }) + + await OneSignal.setExternalUserId(uid) + } + + const sendMagicLink = async (event: React.FormEvent) => { + event.preventDefault() + const { email } = Object.fromEntries(new FormData(event.currentTarget)) + if (typeof email !== 'string') return + + const { error } = await supabase.auth.signInWithOtp({ email }) + if (error) { + alert(error.message) + } else { + alert('Check your email inbox') + } + } + + // Place a order with the selected price + const submitOrder = async (event: React.FormEvent) => { + event.preventDefault() + const { price } = Object.fromEntries(new FormData(event.currentTarget)) + if (typeof price !== 'string') return + + const { error } = await supabase + .from('orders') + .insert({ price: Number(price) }) + if (error) { + alert(error.message) + } + } + + useEffect(() => { + const initialize = async () => { + const initialUser = (await supabase.auth.getUser())?.data.user + setUser(initialUser ?? null) + if (initialUser) { + initializeOneSignal(initialUser.id) + } + } + + initialize() + + const authListener = supabase.auth.onAuthStateChange( + async (event, session) => { + const user = session?.user ?? null + setUser(user) + if (user) { + initializeOneSignal(user.id) + } + } + ) + + return () => { + authListener.data.subscription.unsubscribe() + } + }, []) + + return ( + <> + + OneSignal Order Notification App + + + +
    + {user ? ( +
    + + +
    + ) : ( +
    + + +
    + )} +
    + + ) +} + +export default Home +``` + +There is quite a bit of stuff going on here, but basically, it’s creating a simple UI for the user to sign in using the [magic link](https://supabase.com/docs/guides/auth/auth-magic-link), and once the user is signed in, will initialize OneSignal to ask the user to receive notifications on the website. + +Notice that inside the `initializeOneSignal()` function, we are setting the Supabase user ID as an [external user ID of OneSignal](https://documentation.onesignal.com/docs/external-user-ids). This allows us to later send push notifications to the user using their Supabase user ID from the backend, which is very handy. + +```tsx +await OneSignal.setExternalUserId(uid); +``` + +The front-end side of things is done here. Let’s get into the backend. + +We also need to set our environment variables. Create a `.env.local` file and use the following template to set the environment variables. You can find your Supabase configuration in your dashboard under `settings > API`, and you can find the OneSignal app ID from `Settings > Keys & IDs` + +```bash +NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL +NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY +NEXT_PUBLIC_ONESIGNAL_APP_ID=YOUR_ONESIGNAL_APP_ID +``` + +![Where to find OneSignal App ID](/docs/img/guides/integrations/onesignal/onesignal-app-id.png) + +## Step 3: Create the Edge Function + +Let’s create an edge function that will receive [database webhooks](https://supabase.com/docs/guides/database/webhooks) from the database and calls the OneSignal API to send the push notification. + +```bash +supabase functions new notify +``` + +Replace the contents of `supabase/functions/notify/index.ts` with the following + +```tsx +import { serve } from 'https://deno.land/std@0.131.0/http/server.ts' +import * as OneSignal from 'https://esm.sh/@onesignal/node-onesignal@1.0.0-beta7' + +const _OnesignalAppId_ = Deno.env.get('ONESIGNAL_APP_ID')! +const _OnesignalUserAuthKey_ = Deno.env.get('USER_AUTH_KEY')! +const _OnesignalRestApiKey_ = Deno.env.get('ONESIGNAL_REST_API_KEY')! +const configuration = OneSignal.createConfiguration({ + userKey: _OnesignalUserAuthKey_, + appKey: _OnesignalRestApiKey_, +}) + +const onesignal = new OneSignal.DefaultApi(configuration) + +serve(async (req) => { + try { + const { record } = await req.json() + + // Build OneSignal notification object + const notification = new OneSignal.Notification() + notification.app_id = _OnesignalAppId_ + notification.include_external_user_ids = [record.user_id] + notification.contents = { + en: `You just spent $${record.price}!`, + } + const onesignalApiRes = await onesignal.createNotification(notification) + + return new Response( + JSON.stringify({ onesignalResponse: onesignalApiRes }), + { + headers: { 'Content-Type': 'application/json' }, + } + ) + } catch (err) { + console.error('Failed to create OneSignal notification', err) + return new Response('Server error.', { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } +}) +``` + +If you see bunch of errors in your editor, it's because your editor is not configured to use Deno. Follow the official setup guide [here](https://deno.land/manual@v1.28.3/getting_started/setup_your_environment) to setup your IDE to use Deno. + +The function receives a `record` object, which is the row inserted in your `orders` table, and constructs a notification object to then send to OneSignal to deliver the push notification. + +We also need to set the environment variable for the function. Create a `.env` file under your `supabase` directory and paste the following. + +```bash +ONESIGNAL_APP_ID=YOUR_ONESIGNAL_APP_ID +USER_AUTH_KEY=YOUR_USER_AUTH_KEY +ONESIGNAL_REST_API_KEY=YOUR_ONESIGNAL_REST_API_KEY +``` + +`ONESIGNAL_APP_ID` and `ONESIGNAL_REST_API_KEY` can be found under `Settings > Keys & IDs` of your OneSignal app, and `USER_AUTH_KEY` can be found by going to `Account & API Keys` page by clicking your icon in the top right corner and scrolling to the `User Auth Key` section. + +![Where to find OneSignal User Auth Key](/docs/img/guides/integrations/onesignal/onesignal-api-key.png) + + +Once your environment variables are filled in, you can run the following command to set the environment variable. + +```bash +supabase secrets set --env-file ./supabase/.env +``` + +At this point, the function should be ready to be deployed! Run the following command to deploy your functions to the edge! The `no-verify-jwt` flag is required if you plan to call the function from a webhook. + +```bash +supabase functions deploy notify --no-verify-jwt +``` + +## Step 4: Setting up the Supabase database + +Finally, we get to set up the database! Run the following SQL to set up the `orders` table. + +```sql +create table if not exists public.orders ( + id uuid not null primary key default uuid_generate_v4(), + created_at timestamptz not null default now(), + user_id uuid not null default auth.uid(), + price int8 not null +); +``` + +As you can see, the `orders` table has 4 columns and 3 of them have default values. That means all we need to send from the front-end app is the price. That is why our insert statement looked very simple. + +```tsx +const { error } = await supabase.from('orders').insert({ + price: 100, + }) +``` + +Let’s also set up the webhook so that whenever a new row is inserted in the `orders` table, it calls the edge function. Go to `Database > Webhooks` and create a new Database Webhook. The table should be set to `orders` and Events should be inserted. The type should be HTTP Request, the HTTP method should be POST, and the URL should be the URL of your edge function. Hit confirm to save the webhook configuration. + +![Supabase Webhooks configuration](/docs/img/guides/integrations/onesignal/webhook.png) + +At this point, the app should be complete! Run your app locally with `npm run dev`, or deploy your app to a hosting service and see how you receive a push notification when you place an order! +Remember that if you decide to deploy your app to a hosting service, you would need to create another OneSignal app configured for your local address. + +![Ordering app UI](/docs/img/guides/integrations/onesignal/app-ui.png) + + +## Resources + +This particular example was using Next.js, but you can apply the same principles to implement send push notification, SMS, Emails, and in-app-notifications on other platforms as well. + +- [OneSignal + Flutter + Supabase example](https://github.com/OneSignalDevelopers/onesignal-supabase-sample-integration-supabase) +- [OneSignal Mobile Quickstart](https://documentation.onesignal.com/docs/mobile-sdk-setup) +- [OneSignal Documentation](https://documentation.onesignal.com/docs/onesignal-platform) +- [OneSignal Onboarding guide](https://documentation.onesignal.com/docs/onboarding-with-onesignal) + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/platform/access-control.mdx b/apps/docs/pages/guides/platform/access-control.mdx index f470d14af9a..b12d566cc0c 100644 --- a/apps/docs/pages/guides/platform/access-control.mdx +++ b/apps/docs/pages/guides/platform/access-control.mdx @@ -1,84 +1,81 @@ import Layout from '~/layouts/DefaultGuideLayout' +import { IconCheck } from 'ui' export const meta = { title: 'Access Control', description: 'Roles and permissions at the organization level', } -Supabase provides granular access control features that let you manage permissions across your organizations. - -Within a Supabase organization, a member can have one of the following roles: +Supabase provides granular access controls to manage permissions across your organizations. +For each organization, a member can have one of the following roles: - Owner - Administrator - Developer -A default organization is created for a user when they first sign-in and -assigned the **Owner** role. If the user wants to invite others -to collaborate within the organization, they can visit the organization team -settings (`https://app.supabase.com/org//settings#team`) to send an -invite link to another user's email. The invite expires after 24 hours. - -Invites sent from a SSO account can only be accepted by another SSO account -coming from the same identity provider. This is a security measure that -prevents accidental invites to accounts not managed by your company's -enterprise systems. - -Project level invites are not available at this time. A member of the -organization will be able to access all projects under the organization. If you -wish to restrict access to certain projects, please create another organization -to manage this. +A default organization is created when you first sign in and +you'll be assigned the **Owner** role. +Each member can access all projects under the organization. +Project level invites are not available at this time. +Create a separate organization if you need to restrict access to certain projects. ## Manage team members -You can invite your team members into your organizations to collaborate on projects. +To invite others to collaborate, visit your organization's team settings in the +[Dashboard](https://app.supabase.com/projects) to send an invite link to +another user's email. The invite expires after 24 hours. - +### Transferring ownership of an organization + +Each Supabase organization can have one or more owners. If you no longer want be an owner of an organization, click **Leave team** in the members view (`https://app.supabase.com/org//settings#team`) of your organization. +However, you can only leave an organization when there is _at least one other owner_. + +If you are transferring ownership of your organization to someone else, you will need to invite the new member with the **Owner** role. You can leave the organization after they've accepted the invitation. ### Permissions across roles [#permission-across-roles] The table below shows the corresponding permissions for each available role you can assign a team member in the Dashboard. -| Permissions | Owner | Administrator | Developer | -| ------------------------ | ----- | ------------- | --------- | +| Permissions | Owner | Administrator | Developer | +| ------------------------ | ----------------------- | ----------------------- | ----------------------- | | **Organization** | -| Change organization name | ✅ | | | -| Delete organization | ✅ | | | +| Change organization name | | | | +| Delete organization | | | | | **Members** | -| Add an Owner | ✅ | | | -| Remove an Owner | ✅ | | | -| Add an Administrator | ✅ | ✅ | | -| Remove an Administrator | ✅ | ✅ | | -| Add a Developer | ✅ | ✅ | | -| Remove a Developer | ✅ | ✅ | | -| Revoke an invite | ✅ | ✅ | | -| Resend an invite | ✅ | ✅ | | -| Accept an invite[^1] | ✅ | ✅ | ✅ | +| Add an Owner | | | | +| Remove an Owner | | | | +| Add an Administrator | | | | +| Remove an Administrator | | | | +| Add a Developer | | | | +| Remove a Developer | | | | +| Revoke an invite | | | | +| Resend an invite | | | | +| Accept an invite[^1] | | | | | **Billing** | -| Read invoices | ✅ | ✅ | ✅ | -| Read billing email | ✅ | ✅ | ✅ | -| Change billing email | ✅ | | | -| View subscription | ✅ | ✅ | ✅ | -| Update subscription | ✅ | ✅ | | -| Read billing address | ✅ | ✅ | ✅ | -| Update billing address | ✅ | ✅ | | -| Read tax codes | ✅ | ✅ | ✅ | -| Update tax codes | ✅ | ✅ | | -| Read payment methods | ✅ | ✅ | ✅ | -| Update payment methods | ✅ | ✅ | | +| Read invoices | | | | +| Read billing email | | | | +| Change billing email | | | | +| View subscription | | | | +| Update subscription | | | | +| Read billing address | | | | +| Update billing address | | | | +| Read tax codes | | | | +| Update tax codes | | | | +| Read payment methods | | | | +| Update payment methods | | | | | **Projects** | -| Create a project | ✅ | ✅ | | -| Delete a project | ✅ | ✅ | | -| Update a project | ✅ | ✅ | | -| Pause a project | ✅ | ✅ | | -| Resume a project | ✅ | ✅ | | -| Restart a project | ✅ | ✅ | ✅ | +| Create a project | | | | +| Delete a project | | | | +| Update a project | | | | +| Pause a project | | | | +| Resume a project | | | | +| Restart a project | | | | [^1]: - If the invite was sent from a SSO account, it can only be accepted from - a user signed in via the same identity provider. + Invites sent from a SSO account can only be accepted by another SSO account + coming from the same identity provider. This is a security measure that + prevents accidental invites to accounts not managed by your company's + enterprise systems. export const Page = ({ children }) => diff --git a/apps/docs/pages/guides/platform/backups.mdx b/apps/docs/pages/guides/platform/backups.mdx new file mode 100644 index 00000000000..83d606cd856 --- /dev/null +++ b/apps/docs/pages/guides/platform/backups.mdx @@ -0,0 +1,77 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + title: 'Database Backups', + description: 'Learn about the available backup methods for your Supabase project.', +} + +Database backups are an integral part of any disaster recovery plan. Disasters come in many shapes and sizes. It could be as simple as accidentally deleting a table column, the database crashing, or even a natural calamity wiping out the underlying hardware a database is running on. The risks and impact brought by these scenarios can never be fully eliminated, but only minimized or even mitigated. Having database backups is a form of insurance policy. They are essentially snapshots of the database at various points in time. When disaster strikes, database backups allow the project to be brought back to any of these points in time, therefore averting the crisis. + +## Frequency of Backups + +When deciding how often a database should be backed up, the key business metric Recovery Point Objective (RPO) should be considered. RPO is the threshold for how much data, measured in time, a business could lose when disaster strikes. This amount is fully dependent on a business and its underlying requirements. A low RPO would mean that database backups would have to be taken at an increased cadence throughout the day. Each Supabase project has access to two forms of backups, Daily Backups and Point-in-Time Recovery. The agreed upon RPO would be a deciding factor in choosing which solution best fits a project. + + + Database backups do not include objects stored via the Storage API, as the database only includes + metadata about these objects. Restoring an old backup does not restore objects that have been + deleted since then. + + +## Daily Backups + +All Pro and Enterprise tier Supabase projects are backed up automatically on a daily basis. In terms of Recovery Point Objective (RPO), Daily Backups would be suitable for projects willing to lose up to 24 hours worth of data if disaster hits at the most inopportune time. If a lower RPO is required, enabling Point-in-Time Recovery should be considered. + +### Backup Process [#daily-backups-process] + +The PostgreSQL utility [pg_dumpall](https://www.postgresql.org/docs/current/app-pg-dumpall.html) is used to perform daily backups. An SQL file is generated, zipped up, and sent to our storage servers for safe keeping. + +![Scheduled backups dashboard](/docs/img/backups-daily-dashboard.png) + +You can access daily backups in the [Scheduled backups](https://app.supabase.com/project/_/database/backups/scheduled) settings in the Dashboard. Pro tier projects can access the last 7 days’ worth of daily backups while Enterprise tier projects can access up to 30 days’ worth of daily backups. Users can restore their project to any one of the backups or download them as a zipped SQL file. + +### Restoration Process [#daily-backups-restoration-process] + +When selecting a backup to restore to, select the closest available one made before the desired point in time to restore to. Earlier backups can always be chosen too but do consider the number of days’ worth of data that could be lost. + +![Scheduled backups: Confirmation modal](/docs/img/backups-daily-confirmation-modal.png) + +The Dashboard will then prompt for a confirmation before proceeding with the restoration. The project will be inaccessible following this. As such, do ensure to allot downtime beforehand. This is dependent on the size of the database. The larger it is, the longer the downtime will be. Once the confirmation has been given, the underlying SQL of the chosen backup is then run against the project. The PostgreSQL utility [psql](https://www.postgresql.org/docs/current/app-psql.html) is used to facilitate the restoration. The Dashboard will display a notification once the restoration completes. + +{/* screenshot of the Dashboard of the project completing restoration */} + +## Point-in-Time Recovery + +Point-in-Time Recovery (PITR) allows a project to be backed up at much shorter intervals. This provides users an option to restore to any chosen point of up to seconds in granularity. Even with daily backups, a day’s worth of data could still be lost. With PITR, backups could be performed up to the point of disaster. + + + This feature is available to all Enterprise tier projects. Pro tier projects can enable PITR as an + add-on. + + +### Backup Process [#pitr-backup-process] + +As discussed [here](https://supabase.com/blog/postgresql-physical-logical-backups), PITR is made possible by a combination of taking physical backups of a project, as well as archiving [Write Ahead Log (WAL)](https://www.postgresql.org/docs/current/wal-intro.html) files. Physical backups provide a snapshot of the underlying directory of the database, while WAL files contain records of every change made in the database. + +Supabase uses [WAL-G](https://github.com/wal-g/wal-g), an open source archival and restoration tool, to handle both aspects of PITR. On a daily basis, a snapshot of the database is taken and sent to our storage servers. Throughout the day, as database transactions occur, WAL files are generated and uploaded. + +By default, WAL files are backed up at two minute intervals. If these files cross a certain file size threshold, they are backed up immediately. As such, during periods of high amount of transactions, WAL file backups become more frequent. Conversely, when there is no activity in the database, WAL file backups are not made. Overall, this would mean that at the worst case scenario or disaster, the PITR achieves a Recovery Point Objective (RPO) of two minutes. + +![PITR dashboard](/docs/img/backups-pitr-dashboard.png) + +You can access PITR in the [Point in Time](https://app.supabase.com/project/_/database/backups/pitr) settings in the Dashboard. The recovery period of a project is indicated by the earliest and latest points of recoveries displayed in one’s preferred timezone. If need be, the maximum amount of this recovery period can be modified accordingly. + +Note that the latest restore point of the project could be significantly far from the current time. This occurs when there has not been any recent activity in the database, and therefore no WAL file backups have been made recently. This is perfectly fine as the state of the database at the latest point of recovery would still be indicative of the state of the database at the current time given that no transactions have been made in between. + +### Restoration Process [#pitr-restoration-process] + +![PITR: Calendar view](/docs/img/backups-pitr-calendar-view.png) + +A date and time picker will be provided upon pressing the `Start a restore` button. The process will only proceed if the selected date and time fall within the earliest and latest points of recoveries. + +![PITR: Confirmation modal](/docs/img/backups-pitr-confirmation-modal.png) + +After locking in the desired point in time to recover to, The Dashboard will then prompt for a review and confirmation before proceeding with the restoration. The project will be inaccessible following this. As such, do ensure to allot for downtime beforehand. This is dependent on the size of the database. The larger it is, the longer the downtime will be. Once the confirmation has been given, the latest physical backup available is downloaded to the project and the database is partially restored. WAL files generated after this physical backup up to the specified point-in-time are then downloaded. The underlying records of transactions in these files are replayed against the database to complete the restoration. The Dashboard will display a notification once the restoration completes. + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/platform/custom-domains.mdx b/apps/docs/pages/guides/platform/custom-domains.mdx index 2690eb5f23b..01249cf5455 100644 --- a/apps/docs/pages/guides/platform/custom-domains.mdx +++ b/apps/docs/pages/guides/platform/custom-domains.mdx @@ -12,18 +12,20 @@ Custom Domains are currently in beta, and are being slowly made available to pro -Custom domains allow you to present a branded experience to your users. Currently, you must use a subdomain (e.g., `api.example.com`, rather than `example.com`) for the purposes of this guide. +Custom domains allow you to present a branded experience to your users. Custom domains are available as a [add-on for projects on a paid tier](https://app.supabase.com/project/_/settings/billing/update). Setting up a custom domain requires [Owner or Admin permissions](/docs/guides/platform/access-control#manage-team-members) for the project. Currently, you must use a subdomain (e.g., `api.example.com`, rather than `example.com`) for the purposes of this guide. + +## Configure a Custom Domain using the Supabase Dashboard + +Follow the **Custom Domains** steps in the [General Settings](https://app.supabase.com/project/_/settings/general) page in the Dashboard to set up a custom domain for your project. + +## Configure a Custom Domain using the Supabase CLI + +This example assumes your Supabase project is `foobarbaz` with a corresponding API URL `foobarbaz.supabase.co` and configures a custom domain at `api.example.com`. To get started: -1. [Install](/docs/guides/cli) the Supabase CLI 1.11.3+. -1. [Log in](/docs/guides/cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI. -1. Ensure that you have [Owner or Admin permissions](/docs/guides/platform#manage-team-members) for the project you'd like to set up a custom domain for. -1. Enable the Custom Domains add-on in the Billing page of the Dashboard. - -## Configure a Custom Domain - -This example assumes your Supabase project is `foobarbaz` with a corresponding API URL `foobarbaz.supabase.co` and configures a custom domain at `api.example.com`. +1. [Install](/docs/guides/resources/supabase-cli) the Supabase CLI 1.11.3+. +1. [Log in](/docs/guides/resources/supabase-cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI. ### Configure a CNAME @@ -47,7 +49,7 @@ Required outstanding validation records: api.example.com TXT -> ca3-F1HvR9i938OgVwpCFwi1jTsbhe1hvT0Ic3efPY3Q ``` -[^1] One of the records requires you to _replace_ the CNAME record set up in [the first step](#cname-configure) with a TXT record. You'll be able to restore it back to the CNAME after the verification process has been completed. +[^1] One of the records requires you to _replace_ the CNAME record set up in [the first step](#configure-a-cname) with a TXT record. You'll be able to restore it back to the CNAME after the verification process has been completed. ### Verify your domain @@ -97,9 +99,9 @@ Vanity Subdomains allow you to present a basic branded experience, compared to c To get started: -1. [Install](/docs/guides/cli) the Supabase CLI 1.22.0+. -1. [Log in](/docs/guides/cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI. -1. Ensure that you have [Owner or Admin permissions](/docs/guides/hosting/platform#manage-team-members) for the project you'd like to set up a vanity subdomain for. +1. [Install](/docs/guides/resources/supabase-cli) the Supabase CLI 1.22.0+. +1. [Log in](/docs/guides/resources/supabase-cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI. +1. Ensure that you have [Owner or Admin permissions](/docs/guides/platform/access-control#manage-team-members) for the project you'd like to set up a vanity subdomain for. 1. Ensure that your project has a paid subscription (Pro/Pay as you go/Enterprise tier) in the [Billing page of the Dashboard](https://app.supabase.com/project/_/settings/billing/subscription). ## Configure a Vanity Subdomain diff --git a/apps/docs/pages/guides/platform/going-into-prod.mdx b/apps/docs/pages/guides/platform/going-into-prod.mdx index cfb579ce518..73c25d0a1c5 100644 --- a/apps/docs/pages/guides/platform/going-into-prod.mdx +++ b/apps/docs/pages/guides/platform/going-into-prod.mdx @@ -54,10 +54,31 @@ After developing your project and deciding it's Production Ready, you should run - Supabase employs a number of safeguards against bursts of incoming traffic to prevent abuse and help maximize stability across the platform - If you're expecting high load events including production launches or heavy load testing, or prolonged high resource usage please give us at least 2 weeks notice. You can do this by opening a ticket via the [support form](https://app.supabase.com/support/new). +### Rate Limits + +- The table below shows the rate limit quotas on the following authentication endpoints: + +| Endpoint | Path | Limited By | Rate Limit | +| ------------------------------------------------ | -------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------- | +| All endpoints that send emails | `/auth/v1/signup` `/auth/v1/recover` `/auth/v1/user`[^1] | Sum of combined requests | Defaults to 30 emails per hour. Is customizable with custom SMTP set up. | +| All endpoints that send One-Time-Passwords (OTP) | `/auth/v1/otp` | Sum of combined requests | Defaults to 30 OTPs per hour. Is customizable. | +| Send OTPs or magiclinks | `/auth/v1/otp` | Last request | Defaults to 60 seconds window before a new request is allowed. Is customizable. | +| Signup confirmation request | `/auth/v1/signup` | Last request | Defaults to 60 seconds window before a new request is allowed. Is customizable. | +| Password Reset Request | `/auth/v1/recover` | Last request | Defaults to 60 seconds window before a new request is allowed. Is customizable. | +| Verification requests | `/auth/v1/verify` | IP Address | 360 requests per hour (with bursts up to 30 requests) | +| Token refresh requests | `/auth/v1/token` | IP Address | 360 requests per hour (with bursts up to 30 requests) | +| Create or Verify an MFA challenge | `/auth/v1/factors/:id/challenge` `/auth/v1/factors/:id/verify` | IP Address | 15 requests per minute (with bursts up to 30 requests) | + +### Abuse Prevention + +- Supabase provides CAPTCHA protection on the signup, sign-in and password reset endpoints. Please refer to [our guide](/docs/guides/auth/auth-captcha) on how to protect against abuse using this method. + ## Next steps This checklist is always growing so be sure to check back frequently, and also feel free to suggest additions and amendments by making a PR on [GitHub](https://github.com/supabase/supabase). +[^1]: The rate limit is only applied on `/auth/v1/user` if this endpoint is called to update the user's email address. + export const Page = ({ children }) => export default Page diff --git a/apps/docs/pages/guides/platform/network-restrictions.mdx b/apps/docs/pages/guides/platform/network-restrictions.mdx index 7dfde6433cd..c2286c6a4f5 100644 --- a/apps/docs/pages/guides/platform/network-restrictions.mdx +++ b/apps/docs/pages/guides/platform/network-restrictions.mdx @@ -20,7 +20,7 @@ To get started: 1. [Install](/docs/guides/cli) the Supabase CLI 1.22.0+. 1. [Log in](/docs/guides/cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI. -1. Ensure that you have [Owner or Admin permissions](/docs/guides/hosting/platform#manage-team-members) for the project that you are enabling network restrictions. +1. Ensure that you have [Owner or Admin permissions](/docs/guides/hosting/platform/access-control#manage-team-members) for the project that you are enabling network restrictions. ## Check restrictions diff --git a/apps/docs/pages/guides/realtime/postgres-changes.mdx b/apps/docs/pages/guides/realtime/postgres-changes.mdx index 79a76e884b2..0d68f25c2ef 100644 --- a/apps/docs/pages/guides/realtime/postgres-changes.mdx +++ b/apps/docs/pages/guides/realtime/postgres-changes.mdx @@ -63,7 +63,14 @@ const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY */ const channel = supabase .channel('schema-db-changes') - .on('postgres_changes', { event: '*', schema: 'public' }, (payload) => console.log(payload)) + .on( + 'postgres_changes', + { + event: '*', + schema: 'public', + }, + (payload) => console.log(payload) + ) .subscribe() ``` @@ -74,8 +81,14 @@ To listen to changes on a table in the `public` schema: const channel = supabase .channel('table-db-changes') - .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, (payload) => - console.log(payload) + .on( + 'postgres_changes', + { + event: 'INSERT', + schema: 'public', + table: 'messages', + }, + (payload) => console.log(payload) ) .subscribe() ``` @@ -109,11 +122,21 @@ const channel = supabase .channel('db-changes') .on( 'postgres_changes', - { event: '*', schema: 'public', table: 'messages', filter: 'body=eq.bye' }, + { + event: '*', + schema: 'public', + table: 'messages', + filter: 'body=eq.bye', + }, (payload) => console.log(payload) ) - .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'users' }, (payload) => - console.log(payload) + .on('postgres_changes', + { + event: 'INSERT', + schema: 'public', + table: 'users', + }, + (payload) => console.log(payload) ) .subscribe() ``` diff --git a/apps/docs/pages/guides/resources/self-hosting/docker.mdx b/apps/docs/pages/guides/resources/self-hosting/docker.mdx index db9bcdf0563..ab14e78b0eb 100644 --- a/apps/docs/pages/guides/resources/self-hosting/docker.mdx +++ b/apps/docs/pages/guides/resources/self-hosting/docker.mdx @@ -102,6 +102,10 @@ Once you have done this, you can safely comment out the `db` section of the `doc By default, `docker-compose` sets the database's `log_min_messages` configuration to `fatal` to prevent redundant logs generated by Realtime. However, you might miss important log messages such as database errors. Configure `log_min_messages` based on your needs. +### File storage backend on macOS + +By default, Storage backend is set to `file`, which is to use local files as the storage backend. To make it work on macOS, you need to choose `VirtioFS` as the Docker container file sharing implementation (in Docker Desktop -> Preferences -> General). + ## Deploying See the following guides to deploy Docker Compose setup using your preferred tool and platform: diff --git a/apps/docs/public/img/backups-daily-confirmation-modal.png b/apps/docs/public/img/backups-daily-confirmation-modal.png new file mode 100644 index 00000000000..e340cb7d738 Binary files /dev/null and b/apps/docs/public/img/backups-daily-confirmation-modal.png differ diff --git a/apps/docs/public/img/backups-daily-dashboard.png b/apps/docs/public/img/backups-daily-dashboard.png new file mode 100644 index 00000000000..b6f3b03d443 Binary files /dev/null and b/apps/docs/public/img/backups-daily-dashboard.png differ diff --git a/apps/docs/public/img/backups-pitr-calendar-view.png b/apps/docs/public/img/backups-pitr-calendar-view.png new file mode 100644 index 00000000000..1a4b585b515 Binary files /dev/null and b/apps/docs/public/img/backups-pitr-calendar-view.png differ diff --git a/apps/docs/public/img/backups-pitr-confirmation-modal.png b/apps/docs/public/img/backups-pitr-confirmation-modal.png new file mode 100644 index 00000000000..a365164ef14 Binary files /dev/null and b/apps/docs/public/img/backups-pitr-confirmation-modal.png differ diff --git a/apps/docs/public/img/backups-pitr-dashboard.png b/apps/docs/public/img/backups-pitr-dashboard.png new file mode 100644 index 00000000000..4d68ad5f27f Binary files /dev/null and b/apps/docs/public/img/backups-pitr-dashboard.png differ diff --git a/apps/docs/public/img/guides/integrations/onesignal/app-ui.png b/apps/docs/public/img/guides/integrations/onesignal/app-ui.png new file mode 100644 index 00000000000..aad025d861c Binary files /dev/null and b/apps/docs/public/img/guides/integrations/onesignal/app-ui.png differ diff --git a/apps/docs/public/img/guides/integrations/onesignal/diagram.png b/apps/docs/public/img/guides/integrations/onesignal/diagram.png new file mode 100644 index 00000000000..77b83ca5315 Binary files /dev/null and b/apps/docs/public/img/guides/integrations/onesignal/diagram.png differ diff --git a/apps/docs/public/img/guides/integrations/onesignal/onesignal-api-key.png b/apps/docs/public/img/guides/integrations/onesignal/onesignal-api-key.png new file mode 100644 index 00000000000..439fbec58da Binary files /dev/null and b/apps/docs/public/img/guides/integrations/onesignal/onesignal-api-key.png differ diff --git a/apps/docs/public/img/guides/integrations/onesignal/onesignal-app-id.png b/apps/docs/public/img/guides/integrations/onesignal/onesignal-app-id.png new file mode 100644 index 00000000000..7e5672c05f3 Binary files /dev/null and b/apps/docs/public/img/guides/integrations/onesignal/onesignal-app-id.png differ diff --git a/apps/docs/public/img/guides/integrations/onesignal/webhook.png b/apps/docs/public/img/guides/integrations/onesignal/webhook.png new file mode 100644 index 00000000000..e09c2387721 Binary files /dev/null and b/apps/docs/public/img/guides/integrations/onesignal/webhook.png differ diff --git a/apps/docs/public/img/integrations/logos/onesignal_logo.png b/apps/docs/public/img/integrations/logos/onesignal_logo.png new file mode 100644 index 00000000000..c3d86f11297 Binary files /dev/null and b/apps/docs/public/img/integrations/logos/onesignal_logo.png differ diff --git a/apps/docs/public/sitemap.xml b/apps/docs/public/sitemap.xml index 91ddce8fdf8..f98257a34a2 100644 --- a/apps/docs/public/sitemap.xml +++ b/apps/docs/public/sitemap.xml @@ -1,41 +1,11 @@ - - https://supabase.com/docs - weekly - 0.5 - - - - https://supabase.com/docs/oss - weekly - 0.5 - - - - https://supabase.com/docs/404 - weekly - 0.5 - - - - https://supabase.com/docs/architecture - weekly - 0.5 - - https://supabase.com/docs/faq weekly 0.5 - - https://supabase.com/docs/features - weekly - 0.5 - - https://supabase.com/docs/getting-started weekly @@ -43,13 +13,7 @@ - https://supabase.com/ - weekly - 0.5 - - - - https://supabase.com/docs/ref-pages + https://supabase.com/docs/index weekly 0.5 @@ -72,30 +36,12 @@ 0.5 - - https://supabase.com/supasquad - weekly - 0.5 - - https://supabase.com/docs/guides/api weekly 0.5 - - https://supabase.com/docs/guides/auth - weekly - 0.5 - - - - https://supabase.com/docs/guides/cli - weekly - 0.5 - - https://supabase.com/docs/guides/database weekly @@ -157,85 +103,7 @@ - https://supabase.com/docs/guides/with-angular - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-expo - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-flutter - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-ionic-angular - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-ionic-react - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-ionic-vue - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-nextjs - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-nuxt-3 - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-react - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-redwoodjs - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-solidjs - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-svelte - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-sveltekit - weekly - 0.5 - - - - https://supabase.com/docs/guides/with-vue-3 + https://supabase.com/docs/tutorials/nextjs weekly 0.5 @@ -252,72 +120,12 @@ 0.5 - - https://supabase.com/docs/new/index - weekly - 0.5 - - - - https://supabase.com/docs/tutorials/nextjs - weekly - 0.5 - - - - https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts - weekly - 0.5 - - - - https://supabase.com/docs/learn/auth-deep-dive/auth-google-oauth - weekly - 0.5 - - - - https://supabase.com/docs/learn/auth-deep-dive/auth-gotrue - weekly - 0.5 - - - - https://supabase.com/docs/learn/auth-deep-dive/auth-policies - weekly - 0.5 - - - - https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security - weekly - 0.5 - - https://supabase.com/docs/guides/api/generating-types weekly 0.5 - - https://supabase.com/docs/guides/auth/auth-apple - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-azure - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-bitbucket - weekly - 0.5 - - https://supabase.com/docs/guides/auth/auth-captcha weekly @@ -325,7 +133,7 @@ - https://supabase.com/docs/guides/auth/auth-discord + https://supabase.com/docs/guides/auth/auth-email-templates weekly 0.5 @@ -336,120 +144,24 @@ 0.5 - - https://supabase.com/docs/guides/auth/auth-facebook - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-github - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-gitlab - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-google - weekly - 0.5 - - https://supabase.com/docs/guides/auth/auth-helpers weekly 0.5 - - https://supabase.com/docs/guides/auth/auth-keycloak - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-linkedin - weekly - 0.5 - - https://supabase.com/docs/guides/auth/auth-magic-link weekly 0.5 - - https://supabase.com/docs/guides/auth/auth-messagebird - weekly - 0.5 - - https://supabase.com/docs/guides/auth/auth-mfa weekly 0.5 - - https://supabase.com/docs/guides/auth/auth-notion - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-slack - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-spotify - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-twilio - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-twitch - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-twitter - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-vonage - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-workos - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/auth-zoom - weekly - 0.5 - - https://supabase.com/docs/guides/auth/managing-user-data weekly @@ -486,66 +198,6 @@ 0.5 - - https://supabase.com/docs/guides/cli/local-development - weekly - 0.5 - - - - https://supabase.com/docs/guides/cli/managing-environments - weekly - 0.5 - - - - https://supabase.com/docs/guides/functions/auth - weekly - 0.5 - - - - https://supabase.com/docs/guides/functions/best-practices - weekly - 0.5 - - - - https://supabase.com/docs/guides/functions/cicd-workflow - weekly - 0.5 - - - - https://supabase.com/docs/guides/functions/quickstart - weekly - 0.5 - - - - https://supabase.com/docs/guides/getting-started/architecture - weekly - 0.5 - - - - https://supabase.com/docs/guides/getting-started/features - weekly - 0.5 - - - - https://supabase.com/docs/guides/hosting/docker - weekly - 0.5 - - - - https://supabase.com/docs/guides/hosting/overview - weekly - 0.5 - - https://supabase.com/docs/guides/database/arrays weekly @@ -636,6 +288,42 @@ 0.5 + + https://supabase.com/docs/guides/functions/auth + weekly + 0.5 + + + + https://supabase.com/docs/guides/functions/best-practices + weekly + 0.5 + + + + https://supabase.com/docs/guides/functions/cicd-workflow + weekly + 0.5 + + + + https://supabase.com/docs/guides/functions/quickstart + weekly + 0.5 + + + + https://supabase.com/docs/guides/getting-started/architecture + weekly + 0.5 + + + + https://supabase.com/docs/guides/getting-started/features + weekly + 0.5 + + https://supabase.com/docs/guides/integrations/appsmith weekly @@ -708,6 +396,12 @@ 0.5 + + https://supabase.com/docs/guides/integrations/onesignal + weekly + 0.5 + + https://supabase.com/docs/guides/integrations/pgmustard weekly @@ -775,67 +469,13 @@ - https://supabase.com/docs/guides/realtime/postgres-changes + https://supabase.com/docs/guides/platform/access-control weekly 0.5 - https://supabase.com/docs/guides/realtime/quickstart - weekly - 0.5 - - - - https://supabase.com/docs/guides/realtime/rate-limits - weekly - 0.5 - - - - https://supabase.com/docs/guides/storage/access-control - weekly - 0.5 - - - - https://supabase.com/docs/guides/storage/cdn - weekly - 0.5 - - - - https://supabase.com/docs/guides/storage/quickstart - weekly - 0.5 - - - - https://supabase.com/docs/guides/storage/storage-sample - weekly - 0.5 - - - - https://supabase.com/docs/guides/migrations/firebase-auth - weekly - 0.5 - - - - https://supabase.com/docs/guides/migrations/firebase-storage - weekly - 0.5 - - - - https://supabase.com/docs/guides/migrations/firestore-data - weekly - 0.5 - - - - https://supabase.com/docs/guides/migrations/heroku + https://supabase.com/docs/guides/platform/backups weekly 0.5 @@ -882,6 +522,12 @@ 0.5 + + https://supabase.com/docs/guides/platform/network-restrictions + weekly + 0.5 + + https://supabase.com/docs/guides/platform/performance weekly @@ -895,7 +541,25 @@ - https://supabase.com/docs/guides/resources/examples + https://supabase.com/docs/guides/platform/sso + weekly + 0.5 + + + + https://supabase.com/docs/guides/realtime/postgres-changes + weekly + 0.5 + + + + https://supabase.com/docs/guides/realtime/quickstart + weekly + 0.5 + + + + https://supabase.com/docs/guides/realtime/rate-limits weekly 0.5 @@ -906,12 +570,6 @@ 0.5 - - https://supabase.com/docs/guides/resources/migrating-to-supabase - weekly - 0.5 - - https://supabase.com/docs/guides/resources/self-hosting weekly @@ -924,6 +582,84 @@ 0.5 + + https://supabase.com/docs/guides/storage/access-control + weekly + 0.5 + + + + https://supabase.com/docs/guides/storage/cdn + weekly + 0.5 + + + + https://supabase.com/docs/guides/storage/image-transformations + weekly + 0.5 + + + + https://supabase.com/docs/guides/storage/quickstart + weekly + 0.5 + + + + https://supabase.com/docs/guides/storage/storage-sample + weekly + 0.5 + + + + https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts + weekly + 0.5 + + + + https://supabase.com/docs/learn/auth-deep-dive/auth-google-oauth + weekly + 0.5 + + + + https://supabase.com/docs/learn/auth-deep-dive/auth-gotrue + weekly + 0.5 + + + + https://supabase.com/docs/learn/auth-deep-dive/auth-policies + weekly + 0.5 + + + + https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/phone-login/messagebird + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/phone-login/twilio + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/phone-login/vonage + weekly + 0.5 + + https://supabase.com/docs/guides/auth/auth-helpers/auth-ui weekly @@ -961,19 +697,181 @@ - https://supabase.com/docs/guides/getting-started/quickstarts/nextjs + https://supabase.com/docs/guides/database/extensions/http weekly 0.5 - https://supabase.com/docs/guides/getting-started/quickstarts/nuxtjs + https://supabase.com/docs/guides/database/extensions/pgcron weekly 0.5 - https://supabase.com/docs/guides/getting-started/quickstarts/reactjs + https://supabase.com/docs/guides/database/extensions/pgnet + weekly + 0.5 + + + + https://supabase.com/docs/guides/database/extensions/pgtap + weekly + 0.5 + + + + https://supabase.com/docs/guides/database/extensions/plv8 + weekly + 0.5 + + + + https://supabase.com/docs/guides/database/extensions/uuid-ossp + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-apple + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-azure + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-bitbucket + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-discord + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-facebook + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-github + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-gitlab + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-google + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-keycloak + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-linkedin + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-notion + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-slack + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-spotify + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-twitch + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-twitter + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-workos + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/social-login/auth-zoom + weekly + 0.5 + + + + https://supabase.com/docs/guides/platform/sso/azure + weekly + 0.5 + + + + https://supabase.com/docs/guides/platform/sso/gsuite + weekly + 0.5 + + + + https://supabase.com/docs/guides/platform/sso/okta + weekly + 0.5 + + + + https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-auth + weekly + 0.5 + + + + https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-storage + weekly + 0.5 + + + + https://supabase.com/docs/guides/resources/migrating-to-supabase/firestore-data + weekly + 0.5 + + + + https://supabase.com/docs/guides/resources/migrating-to-supabase/heroku weekly 0.5 @@ -1062,72 +960,6 @@ 0.5 - - https://supabase.com/docs/guides/database/extensions/http - weekly - 0.5 - - - - https://supabase.com/docs/guides/database/extensions/pgcron - weekly - 0.5 - - - - https://supabase.com/docs/guides/database/extensions/pgnet - weekly - 0.5 - - - - https://supabase.com/docs/guides/database/extensions/pgtap - weekly - 0.5 - - - - https://supabase.com/docs/guides/database/extensions/plv8 - weekly - 0.5 - - - - https://supabase.com/docs/guides/database/extensions/uuid-ossp - weekly - 0.5 - - - - https://supabase.com/docs/new/auth/auth-login - weekly - 0.5 - - - - https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-auth - weekly - 0.5 - - - - https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-data - weekly - 0.5 - - - - https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-storage - weekly - 0.5 - - - - https://supabase.com/docs/guides/resources/migrating-to-supabase/heroku - weekly - 0.5 - - https://supabase.com/docs/guides/resources/self-hosting/docker weekly @@ -1135,25 +967,19 @@ - https://supabase.com/docs/guides/auth/auth-magic-link + https://supabase.com/docs/guides/getting-started/quickstarts/nextjs weekly 0.5 - https://supabase.com/docs/guides/auth/phone-login/messagebird + https://supabase.com/docs/guides/getting-started/quickstarts/nuxtjs weekly 0.5 - https://supabase.com/docs/guides/auth/phone-login/twilio - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/phone-login/vonage + https://supabase.com/docs/guides/getting-started/quickstarts/reactjs weekly 0.5 @@ -1165,253 +991,13 @@ - https://supabase.com/docs/guides/resources/supabase-cli/managing-enviroments + https://supabase.com/docs/guides/resources/supabase-cli/managing-environments weekly 0.5 - https://supabase.com/docs/guides/auth/social-login/auth-apple - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-azure - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-bitbucket - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-discord - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-facebook - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-github - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-gitlab - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-google - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-keycloak - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-linkedin - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-notion - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-slack - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-spotify - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-twilio - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-twitch - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-twitter - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-workos - weekly - 0.5 - - - - https://supabase.com/docs/guides/auth/social-login/auth-zoom - weekly - 0.5 - - - - https://supabase.com/docs/reference/api - weekly - 0.5 - - - - https://supabase.com/docs/reference/auth - weekly - 0.5 - - - - https://supabase.com/docs/reference/cli - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript - weekly - 0.5 - - - - https://supabase.com/docs/reference/realtime - weekly - 0.5 - - - - https://supabase.com/docs/reference/storage - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/installing - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/release-notes - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/typescript-support - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/upgrade-guide - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/admin-api - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-createuser - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-deleteuser - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-generatelink - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-getuserbyid - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-inviteuserbyemail - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-invoke - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-listusers - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-mfa-deletefactor - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-mfa-listfactors - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-resetpasswordforemail - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/auth-admin-updateuserbyid + https://supabase.com/docs/reference/javascript/initializing weekly 0.5 @@ -1422,6 +1008,42 @@ 0.5 + + https://supabase.com/docs/reference/javascript/auth-signup + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-signinwithpassword + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-signinwithotp + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-signinwithoauth + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-signout + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-verifyotp + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/auth-getsession weekly @@ -1434,12 +1056,48 @@ 0.5 + + https://supabase.com/docs/reference/javascript/auth-updateuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-setsession + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-refreshsession + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-onauthstatechange + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-mfa-enroll + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/auth-mfa-challenge weekly 0.5 + + https://supabase.com/docs/reference/javascript/auth-mfa-verify + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/auth-mfa-challengeandverify weekly @@ -1447,7 +1105,7 @@ - https://supabase.com/docs/reference/javascript/auth-mfa-enroll + https://supabase.com/docs/reference/javascript/auth-mfa-unenroll weekly 0.5 @@ -1461,25 +1119,37 @@ - https://supabase.com/docs/reference/javascript/auth-mfa-unenroll + https://supabase.com/docs/reference/javascript/admin-api weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-mfa-verify + https://supabase.com/docs/reference/javascript/auth-admin-getuserbyid weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-onauthstatechange + https://supabase.com/docs/reference/javascript/auth-admin-listusers weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-refreshsession + https://supabase.com/docs/reference/javascript/auth-admin-createuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-admin-deleteuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-admin-inviteuserbyemail weekly 0.5 @@ -1491,79 +1161,49 @@ - https://supabase.com/docs/reference/javascript/auth-setsession + https://supabase.com/docs/reference/javascript/auth-admin-generatelink weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-signinwithoauth + https://supabase.com/docs/reference/javascript/auth-admin-updateuserbyid weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-signinwithotp + https://supabase.com/docs/reference/javascript/auth-admin-mfa-listfactors weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-signinwithpassword + https://supabase.com/docs/reference/javascript/auth-admin-mfa-deletefactor weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-signout + https://supabase.com/docs/reference/javascript/select weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-signup + https://supabase.com/docs/reference/javascript/insert weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-updateuser + https://supabase.com/docs/reference/javascript/update weekly 0.5 - https://supabase.com/docs/reference/javascript/auth-verifyotp - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/containedby - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/contains - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/db-abortsignal - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/db-csv - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/db-modifiers-select + https://supabase.com/docs/reference/javascript/upsert weekly 0.5 @@ -1574,6 +1214,18 @@ 0.5 + + https://supabase.com/docs/reference/javascript/rpc + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/using-filters + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/eq weekly @@ -1581,13 +1233,7 @@ - https://supabase.com/docs/reference/javascript/filter - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/getchannels + https://supabase.com/docs/reference/javascript/neq weekly 0.5 @@ -1604,60 +1250,6 @@ 0.5 - - https://supabase.com/docs/reference/javascript/ilike - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/in - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/index - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/initializing - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/insert - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/invoke - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/is - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/like - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/limit - weekly - 0.5 - - https://supabase.com/docs/reference/javascript/lt weekly @@ -1671,55 +1263,37 @@ - https://supabase.com/docs/reference/javascript/match + https://supabase.com/docs/reference/javascript/like weekly 0.5 - https://supabase.com/docs/reference/javascript/maybesingle + https://supabase.com/docs/reference/javascript/ilike weekly 0.5 - https://supabase.com/docs/reference/javascript/neq + https://supabase.com/docs/reference/javascript/is weekly 0.5 - https://supabase.com/docs/reference/javascript/not + https://supabase.com/docs/reference/javascript/in weekly 0.5 - https://supabase.com/docs/reference/javascript/or + https://supabase.com/docs/reference/javascript/contains weekly 0.5 - https://supabase.com/docs/reference/javascript/order - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/overlaps - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/range - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/rangeadjacent + https://supabase.com/docs/reference/javascript/containedby weekly 0.5 @@ -1749,25 +1323,79 @@ - https://supabase.com/docs/reference/javascript/removeallchannels + https://supabase.com/docs/reference/javascript/rangeadjacent weekly 0.5 - https://supabase.com/docs/reference/javascript/removechannel + https://supabase.com/docs/reference/javascript/overlaps weekly 0.5 - https://supabase.com/docs/reference/javascript/rpc + https://supabase.com/docs/reference/javascript/textsearch weekly 0.5 - https://supabase.com/docs/reference/javascript/select + https://supabase.com/docs/reference/javascript/match + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/not + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/or + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/filter + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/using-modifiers + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/db-modifiers-select + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/order + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/limit + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/range + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/db-abortsignal weekly 0.5 @@ -1778,12 +1406,78 @@ 0.5 + + https://supabase.com/docs/reference/javascript/maybesingle + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/db-csv + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/auth-admin-invoke + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/subscribe + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/getchannels + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/removechannel + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/removeallchannels + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/storage-listbuckets + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/storage-getbucket + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/storage-createbucket weekly 0.5 + + https://supabase.com/docs/reference/javascript/storage-emptybucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/storage-updatebucket + weekly + 0.5 + + https://supabase.com/docs/reference/javascript/storage-deletebucket weekly @@ -1791,7 +1485,19 @@ - https://supabase.com/docs/reference/javascript/storage-emptybucket + https://supabase.com/docs/reference/javascript/storage-from-upload + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/storage-from-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/storage-from-move weekly 0.5 @@ -1814,12 +1520,6 @@ 0.5 - - https://supabase.com/docs/reference/javascript/storage-from-download - weekly - 0.5 - - https://supabase.com/docs/reference/javascript/storage-from-getpublicurl weekly @@ -1827,13 +1527,7 @@ - https://supabase.com/docs/reference/javascript/storage-from-list - weekly - 0.5 - - - - https://supabase.com/docs/reference/javascript/storage-from-move + https://supabase.com/docs/reference/javascript/storage-from-download weekly 0.5 @@ -1845,121 +1539,493 @@ - https://supabase.com/docs/reference/javascript/storage-from-update + https://supabase.com/docs/reference/javascript/storage-from-list weekly 0.5 - https://supabase.com/docs/reference/javascript/storage-from-upload + https://supabase.com/docs/reference/javascript/v1/initializing weekly 0.5 - https://supabase.com/docs/reference/javascript/storage-getbucket + https://supabase.com/docs/reference/javascript/v1/auth-signup weekly 0.5 - https://supabase.com/docs/reference/javascript/storage-listbuckets + https://supabase.com/docs/reference/javascript/v1/auth-signin weekly 0.5 - https://supabase.com/docs/reference/javascript/storage-updatebucket + https://supabase.com/docs/reference/javascript/v1/auth-signout weekly 0.5 - https://supabase.com/docs/reference/javascript/subscribe + https://supabase.com/docs/reference/javascript/v1/auth-session weekly 0.5 - https://supabase.com/docs/reference/javascript/supabase-auth-admin-api + https://supabase.com/docs/reference/javascript/v1/auth-user weekly 0.5 - https://supabase.com/docs/reference/javascript/textsearch + https://supabase.com/docs/reference/javascript/v1/auth-update weekly 0.5 - https://supabase.com/docs/reference/javascript/undefined + https://supabase.com/docs/reference/javascript/v1/auth-setauth weekly 0.5 - https://supabase.com/docs/reference/javascript/update + https://supabase.com/docs/reference/javascript/v1/auth-onauthstatechange weekly 0.5 - https://supabase.com/docs/reference/javascript/upsert + https://supabase.com/docs/reference/javascript/v1/auth-getuser weekly 0.5 - https://supabase.com/docs/reference/javascript/using-filters + https://supabase.com/docs/reference/javascript/v1/auth-admin-listusers weekly 0.5 - https://supabase.com/docs/reference/javascript/using-modifiers + https://supabase.com/docs/reference/javascript/v1/auth-admin-createuser weekly 0.5 - https://supabase.com/docs/reference/dart/initializing + https://supabase.com/docs/reference/javascript/v1/auth-admin-deleteuser weekly 0.5 - https://supabase.com/docs/reference/dart/installing + https://supabase.com/docs/reference/javascript/v1/auth-admin-inviteuserbyemail weekly 0.5 - https://supabase.com/docs/reference/dart/upgrade-guide + https://supabase.com/docs/reference/javascript/v1/auth-api-sendmobileotp weekly 0.5 - https://supabase.com/docs/reference/dart/auth-admin-invoke + https://supabase.com/docs/reference/javascript/v1/auth-resetpasswordforemail weekly 0.5 - https://supabase.com/docs/reference/dart/auth-admin-resetpasswordforemail + https://supabase.com/docs/reference/javascript/v1/auth-admin-generatelink weekly 0.5 - https://supabase.com/docs/reference/dart/auth-currentsession + https://supabase.com/docs/reference/javascript/v1/auth-admin-updateuserbyid weekly 0.5 - https://supabase.com/docs/reference/dart/auth-currentuser + https://supabase.com/docs/reference/javascript/v1/auth-admin-invoke + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/select + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/insert + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/update + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/upsert + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rpc + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/subscribe + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/removesubscription + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/removeallsubscriptions + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/getsubscriptions + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-listbuckets + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-getbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-createbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-emptybucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-updatebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-deletebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-upload + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-move + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-copy + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-createsignedurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-createsignedurls + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-getpublicurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-download + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-remove + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/storage-from-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/using-modifiers + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/limit + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/order + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/range + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/single + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/maybesingle + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/using-filters + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/or + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/not + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/match + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/eq + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/neq + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/gt + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/gte + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/lt + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/lte + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/like + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/ilike + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/is + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/in + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/contains + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/containedby + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rangelte + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rangegt + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rangegte + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rangelte + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/rangeadjacent + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/overlaps + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/textsearch + weekly + 0.5 + + + + https://supabase.com/docs/reference/javascript/v1/filter + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-signup + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-signinwithpassword + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-signinwithotp + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-signinwithoauth + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-signout + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/auth-verifyotp weekly 0.5 @@ -1976,48 +2042,6 @@ 0.5 - - https://supabase.com/docs/reference/dart/auth-onauthstatechange - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-resetpasswordforemail - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-signinwithoauth - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-signinwithotp - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-signinwithpassword - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-signout - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/auth-signup - weekly - 0.5 - - https://supabase.com/docs/reference/dart/auth-updateuser weekly @@ -2025,217 +2049,19 @@ - https://supabase.com/docs/reference/dart/auth-verifyotp + https://supabase.com/docs/reference/dart/auth-onauthstatechange weekly 0.5 - https://supabase.com/docs/reference/dart/containedby + https://supabase.com/docs/reference/dart/undefined weekly 0.5 - https://supabase.com/docs/reference/dart/contains - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/delete - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/eq - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/filter - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/getchannels - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/gt - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/gte - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/ilike - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/in - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/in_ - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/index - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/insert - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/invoke - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/is - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/is_ - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/like - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/limit - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/lt - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/lte - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/match - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/neq - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/not - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/or - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/order - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/overlaps - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/range - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rangeadjacent - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rangegt - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rangegte - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rangelt - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rangelte - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/removeallchannels - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/removechannel - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/rpc + https://supabase.com/docs/reference/dart/auth-admin-invoke weekly 0.5 @@ -2247,121 +2073,7 @@ - https://supabase.com/docs/reference/dart/single - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-createbucket - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-deletebucket - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-emptybucket - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-createsignedurl - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-createsignedurls - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-download - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-getpublicurl - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-list - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-move - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-remove - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-update - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-from-upload - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-getbucket - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-listbuckets - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/storage-updatebucket - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/stream - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/subscribe - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/textsearch - weekly - 0.5 - - - - https://supabase.com/docs/reference/dart/undefined + https://supabase.com/docs/reference/dart/insert weekly 0.5 @@ -2379,7 +2091,127 @@ - https://supabase.com/docs/reference/dart/using-filters + https://supabase.com/docs/reference/dart/delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/rpc + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/subscribe + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/removechannel + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/removeallchannels + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/getchannels + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/stream + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-listbuckets + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-getbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-createbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-emptybucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-updatebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-deletebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-upload + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-move + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-createsignedurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-getpublicurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-download + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-remove + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/storage-from-list weekly 0.5 @@ -2391,133 +2223,1467 @@ - https://supabase.com/docs/reference/api/release-notes + https://supabase.com/docs/reference/dart/limit weekly 0.5 - https://supabase.com/docs/reference/api/usage + https://supabase.com/docs/reference/dart/order weekly 0.5 - https://supabase.com/docs/reference/cli/release-notes + https://supabase.com/docs/reference/dart/range weekly 0.5 - https://supabase.com/docs/reference/cli/config + https://supabase.com/docs/reference/dart/single weekly 0.5 - https://supabase.com/docs/reference/cli/usage + https://supabase.com/docs/reference/dart/using-filters weekly 0.5 - https://supabase.com/docs/reference/postgres/changing-timezones + https://supabase.com/docs/reference/dart/or weekly 0.5 - https://supabase.com/docs/reference/postgres/columns + https://supabase.com/docs/reference/dart/not weekly 0.5 - https://supabase.com/docs/reference/postgres/connection-strings + https://supabase.com/docs/reference/dart/match weekly 0.5 - https://supabase.com/docs/reference/postgres/database-passwords + https://supabase.com/docs/reference/dart/eq weekly 0.5 - https://supabase.com/docs/reference/postgres/database-users + https://supabase.com/docs/reference/dart/neq weekly 0.5 - https://supabase.com/docs/reference/postgres/index + https://supabase.com/docs/reference/dart/gt weekly 0.5 - https://supabase.com/docs/reference/postgres/publications + https://supabase.com/docs/reference/dart/gte weekly 0.5 - https://supabase.com/docs/reference/postgres/schemas + https://supabase.com/docs/reference/dart/lt weekly 0.5 - https://supabase.com/docs/reference/postgres/tables + https://supabase.com/docs/reference/dart/lte weekly 0.5 - https://supabase.com/docs/reference/realtime/release-notes + https://supabase.com/docs/reference/dart/like weekly 0.5 - https://supabase.com/docs/reference/realtime/config + https://supabase.com/docs/reference/dart/ilike weekly 0.5 - https://supabase.com/docs/reference/storage/release-notes + https://supabase.com/docs/reference/dart/is weekly 0.5 - https://supabase.com/docs/reference/storage/config + https://supabase.com/docs/reference/dart/in weekly 0.5 - https://supabase.com/docs/reference/storage/usage + https://supabase.com/docs/reference/dart/contains weekly 0.5 - https://supabase.com/docs/reference/auth/release-notes + https://supabase.com/docs/reference/dart/containedby weekly 0.5 - https://supabase.com/docs/reference/auth/config + https://supabase.com/docs/reference/dart/rangelt weekly 0.5 - https://supabase.com/docs/reference/auth/usage + https://supabase.com/docs/reference/dart/rangegt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/rangegte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/rangelte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/rangeadjacent + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/overlaps + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/textsearch + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/filter + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/installing + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/initializing + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signup + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signin + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signinwithprovider + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signout + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-session + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-user + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-getsession + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-getuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-updateuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-onauthstatechange + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-resetpasswordforemail + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-admin-invoke + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/select + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/insert + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/update + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/upsert + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rpc + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/subscribe + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/removesubscription + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/getsubscriptions + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/stream + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-listbuckets + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-getbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-createbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-emptybucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-updatebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-deletebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-upload + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-move + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-createsignedurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-getpublicurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-download + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-remove + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/using-modifiers + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/limit + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/order + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/range + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/single + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/using-filters + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/or + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/not + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/match + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/eq + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/neq + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/gt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/gte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/lt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/lte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/like + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/ilike + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/is + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/in + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/contains + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/containedby + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangelt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangegt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangegte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangelte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangeadjacent + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/overlaps + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/textsearch + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/filter + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/installing + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/initializing + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signup + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signin + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signinwithprovider + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-signout + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-session + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-user + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-getsession + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-getuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-updateuser + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-onauthstatechange + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-resetpasswordforemail + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/auth-admin-invoke + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/select + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/insert + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/update + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/upsert + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rpc + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/subscribe + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/removesubscription + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/getsubscriptions + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/stream + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-listbuckets + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-getbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-createbucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-emptybucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-updatebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-deletebucket + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-upload + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-move + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-createsignedurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-getpublicurl + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-download + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-remove + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/storage-from-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/using-modifiers + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/limit + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/order + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/range + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/single + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/using-filters + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/or + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/not + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/match + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/eq + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/neq + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/gt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/gte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/lt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/lte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/like + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/ilike + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/is + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/in + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/contains + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/containedby + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangelt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangegt + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangegte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangelte + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/rangeadjacent + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/overlaps + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/textsearch + weekly + 0.5 + + + + https://supabase.com/docs/reference/dart/v0/filter + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-vanity-subdomains + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-vanity-subdomains-get + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-vanity-subdomains-delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-vanity-subdomains-check-availability + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-vanity-subdomains-activate + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-test + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-test-db + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-stop + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-status + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-start + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-secrets + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-secrets-unset + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-secrets-set + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-secrets-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-projects + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-projects-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-projects-create + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-orgs + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-orgs-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-network-restrictions + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-network-restrictions-update + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-network-restrictions-get + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-migration + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-migration-repair + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-migration-new + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-migration-list + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-login + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-link + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-init + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-gen + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-gen-types + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-gen-types-typescript + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-functions + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-functions-serve + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-functions-new + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-functions-deploy + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-functions-delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains-reverify + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains-get + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains-delete + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains-create + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-domains-activate + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-reset + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-remote + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-remote-commit + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-push + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-lint + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-db-diff + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-completion + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-completion-zsh + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-completion-powershell + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-completion-fish + weekly + 0.5 + + + + https://supabase.com/docs/reference/cli/supabase-completion-bash + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/introduction + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/list-all-projects + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/create-a-project + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/list-all-organizations + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/create-an-organization + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/list-all-secrets + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/bulk-create-secrets + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/bulk-delete-secrets + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/generate-typescript-types + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/create-a-function + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/list-all-functions + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/retrieve-a-function + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/update-a-function + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/delete-a-function + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/retrieve-a-function-body + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/gets-projects-custom-hostname-config + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/deletes-a-projects-custom-hostname-configuration + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/updates-projects-custom-hostname-configuration + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/attempts-to-verify-the-dns-configuration-for-projects-custom-hostname-configuration + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/activates-a-custom-hostname-for-a-project + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/gets-projects-pgsodium-config + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/updates-projects-pgsodium-config-updating-the-root_key-can-cause-all-data-encrypted-with-the-older-key-to-become-inaccessible + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/gets-projects-network-bans + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/remove-network-bans + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/gets-projects-network-restrictions + weekly + 0.5 + + + + https://supabase.com/docs/reference/api/updates-projects-network-restrictions weekly 0.5 diff --git a/apps/docs/scripts/build-search.js b/apps/docs/scripts/build-search.ts similarity index 59% rename from apps/docs/scripts/build-search.js rename to apps/docs/scripts/build-search.ts index 07865a2344c..1fdc4e18a88 100644 --- a/apps/docs/scripts/build-search.js +++ b/apps/docs/scripts/build-search.ts @@ -1,22 +1,24 @@ -const fs = require('fs') -const crypto = require('crypto') -const path = require('path') -const matter = require('gray-matter') -const dotenv = require('dotenv') -const algoliasearch = require('algoliasearch/lite') -const { isEmpty } = require('lodash') +import fs from 'fs' +import crypto from 'crypto' +import path from 'path' +import matter from 'gray-matter' +import dotenv from 'dotenv' +import algoliasearch from 'algoliasearch/lite' +import { isEmpty } from 'lodash' -// [Joshen] We initially thought of building out our search using Algolia directly, -// but eventually decided to just use DocSearch since it provides us a UI and some -// configurations out of the box (e.g Doc hierarchy). +// search objects +import { generateClientLibSearchObjects } from './files/client-libs' +import { generateAPISearchObjects } from './files/api' +import { generateCLISearchObjects } from './files/cli' -// As such when creating the search object, the properties that are specifically read +const cliObjects = generateCLISearchObjects() +const apiObjects = generateAPISearchObjects() +const clientLibSearchObjects = generateClientLibSearchObjects() + +// @ts-ignore +// The properties of the searchObject that are specifically read // by DocSearch are "type" and "hierarchy". The rest, though saved into Algolia (which we // can potentially use to craft more nuanced search experiences) are not used by DocSearch - -// Note that we'll need to do a general clean up of the files in the docs -// A lot of them are not even linked to within the docs site, so just need to -// double check if they can be removed or if we want them in the side bars. const ignoredFiles = [ 'pages/404.mdx', 'pages/faq.mdx', @@ -30,18 +32,9 @@ const ignoredFiles = [ 'pages/handbook/supasquad.mdx', ] -const nameMap = { - api: 'Management API', - cli: 'Supabase CLI', - auth: 'Auth Server', - storage: 'Storage Server', - postgres: 'Postgres', - dart: 'Supabase Flutter Library', - javascript: 'Supabase JavaScript Library', -} - async function walk(dir) { let files = await fs.promises.readdir(dir) + //@ts-ignore files = await Promise.all( files.map(async (file) => { const filePath = path.join(dir, file) @@ -66,15 +59,6 @@ async function walk(dir) { console.log('Preparing docs indexing for Algolia') - function extractMeta(mdx) { - const regex = /^export\sconst\smeta\s=\s(\{[\w\s':,]*\})/gm - const match = regex.exec(mdx) - if (match) { - return JSON.parse(match[1]) - } - return null - } - try { const indexName = process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME const client = algoliasearch( @@ -83,11 +67,10 @@ async function walk(dir) { ) const index = client.initIndex(indexName) - const referencePages = await walk('docs') const guidePages = (await walk('pages')).filter((slug) => !ignoredFiles.includes(slug)) - const allPages = guidePages.concat(referencePages) - const searchObjects = allPages + // generate search objects for mdx guide pages + const guidePagesearchObjects = guidePages .map((slug) => { let id, title, description const fileContents = fs.readFileSync(slug, 'utf8') @@ -118,6 +101,7 @@ async function walk(dir) { .replace('pages', '') .replace(/\.mdx$/, '') const source = slug.includes('/reference') ? 'reference' : 'guide' + const object = { // For Algolia objectID: crypto.randomUUID(), @@ -126,7 +110,8 @@ async function walk(dir) { description, url, source, - pageContent: content, + //pageContent: content, + pageContent: '', category: undefined, version: undefined, @@ -143,44 +128,26 @@ async function walk(dir) { }, } - if (slug.includes('/reference')) { - const urlSegments = url.split('/') - const category = urlSegments[urlSegments.indexOf('reference') + 1] - const version = urlSegments[urlSegments.indexOf('reference') + 2] || '' - - const hasVersion = /v[0-9]+/.test(version) - if (hasVersion) { - object.version = version - object.type = title === nameMap[category] ? 'lvl2' : 'lvl3' - object.hierarchy.lvl1 = nameMap[category] - object.hierarchy.lvl2 = version - object.hierarchy.lvl3 = title - } else { - const page = urlSegments[urlSegments.indexOf('reference') + 2] - if (page === 'generated') { - } else { - if (page !== undefined) { - object.type = 'lvl2' - object.hierarchy.lvl1 = nameMap[category] - object.hierarchy.lvl2 = title - } - } - } - - object.category = category ? category.replace(/\.mdx$/, '') : undefined - object.hierarchy.lvl0 = 'References' - } - return object }) // Some of the reference generated files come with an 'index' page that we can ignore .filter((object) => !object.url.endsWith('/index')) .filter((object) => !object.url.endsWith('/.gitkeep')) + const combinedSearchObjects = guidePagesearchObjects.concat( + clientLibSearchObjects, + apiObjects, + cliObjects + ) + + //@ts-ignore await index.clearObjects() console.log(`Successfully cleared records from ${indexName}`) - const algoliaResponse = await index.saveObjects(searchObjects) + //@ts-ignore + const algoliaResponse = await index.saveObjects(combinedSearchObjects) + + //@ts-ignore console.log(`Successfully saved ${algoliaResponse.objectIDs.length} records into ${indexName}.`) } catch (error) { console.log('Error:', error) diff --git a/apps/docs/scripts/files/api.ts b/apps/docs/scripts/files/api.ts new file mode 100644 index 00000000000..ed98a9c4921 --- /dev/null +++ b/apps/docs/scripts/files/api.ts @@ -0,0 +1,43 @@ +import crypto from 'crypto' +import { flattenSections } from '../../lib/helpers' + +import apiCommonSections from '~/../../spec/common-api-sections.json' +import specFile from '~/../../spec/transforms/api_v0_openapi_deparsed.json' +import { gen_v3 } from '../../lib/refGenerator/helpers' + +// @ts-ignore +const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' }) +const sections = flattenSections(apiCommonSections) + +export function generateAPISearchObjects() { + let searchObjects = [] + + //@ts-ignore + sections.map((section) => { + const object = searchObjects.push({ + objectID: crypto.randomUUID(), + id: section.id, + title: section.title, + // @ts-ignore + description: generatedSpec.operations.find((item) => item.operationId === section.id) + ?.summary, + url: `/reference/api/${section.slug}`, + source: 'reference', + pageContent: '', + category: section.product, + version: '', + type: 'lvl2', + hierarchy: { + lvl0: 'References', + lvl1: 'Management API', + lvl2: section.title, + lvl3: null, + lvl4: null, + lvl5: null, + lvl6: null, + }, + }) + return object + }) + return searchObjects +} diff --git a/apps/docs/scripts/files/cli.ts b/apps/docs/scripts/files/cli.ts new file mode 100644 index 00000000000..84caae225c6 --- /dev/null +++ b/apps/docs/scripts/files/cli.ts @@ -0,0 +1,43 @@ +import crypto from 'crypto' +import fs from 'fs' +import { flattenSections } from '../../lib/helpers' +import cliCommonSections from '~/../../spec/common-cli-sections.json' +import yaml from 'js-yaml' + +// @ts-ignore + +const spec = yaml.load(fs.readFileSync(`../../spec/cli_v1_commands.yaml`, 'utf8')) + +const commonSections = flattenSections(cliCommonSections) + +export function generateCLISearchObjects() { + let searchObjects = [] + + //@ts-ignore + spec.commands.map((section) => { + const object = searchObjects.push({ + objectID: crypto.randomUUID(), + id: section.id, + title: section.title, + // @ts-ignore + description: section.description?.substr(0, section.description.indexOf('\n')), + url: `/reference/cli/${commonSections.find((item) => item.id === section.id)?.slug}`, + source: 'reference', + pageContent: '', + category: section.product, + version: '', + type: 'lvl2', + hierarchy: { + lvl0: 'References', + lvl1: 'Supabase CLI', + lvl2: section.title, + lvl3: null, + lvl4: null, + lvl5: null, + lvl6: null, + }, + }) + return object + }) + return searchObjects +} diff --git a/apps/docs/scripts/files/client-libs.ts b/apps/docs/scripts/files/client-libs.ts new file mode 100644 index 00000000000..714769ebcc7 --- /dev/null +++ b/apps/docs/scripts/files/client-libs.ts @@ -0,0 +1,57 @@ +import fs from 'fs' +import crypto from 'crypto' +import yaml from 'js-yaml' +import { flattenSections } from '../../lib/helpers' +import { nameMap } from '../helpers' + +import commonLibSections from '~/../../spec/common-client-libs-sections.json' + +const clientLibFiles = [ + { fileName: 'supabase_js_v2', label: 'javascript', version: 'v2', versionSlug: false }, + { fileName: 'supabase_js_v1', label: 'javascript', version: 'v1', versionSlug: true }, + { fileName: 'supabase_dart_v1', label: 'dart', version: 'v1', versionSlug: false }, + { fileName: 'supabase_dart_v0', label: 'dart', version: 'v0', versionSlug: true }, + { fileName: 'supabase_dart_v0', label: 'dart', version: 'v0', versionSlug: true }, +] + +const flatCommonLibSections = flattenSections(commonLibSections) + +export function generateClientLibSearchObjects() { + // loop through each spec file, find the correspending entry in the common file and grab the title / description / slug + let clientLibSearchObjects = [] + + clientLibFiles.map((file) => { + const specs = yaml.load(fs.readFileSync(`../../spec/${file.fileName}.yml`, 'utf8')) + + //take each function id, find it in the commonLibSections file and return { id, title, slug, description, } + //@ts-ignore + specs.functions.map((fn) => { + const item = flatCommonLibSections.find((section) => section.id === fn.id) + if (item) { + const object = clientLibSearchObjects.push({ + objectID: crypto.randomUUID(), + id: item.id, + title: item.title, + description: item.title, + url: `/reference/${file.label}/${file.versionSlug ? file.version + '/' : ''}${item.slug}`, + source: 'reference', + pageContent: '', + category: item.product, + version: file.version, + type: 'lvl2', + hierarchy: { + lvl0: 'References', + lvl1: `${nameMap[file.label]} ${file.version}`, + lvl2: item.title, + lvl3: file.version, + lvl4: null, + lvl5: null, + lvl6: null, + }, + }) + return object + } + }) + }) + return clientLibSearchObjects +} diff --git a/apps/docs/scripts/helpers.ts b/apps/docs/scripts/helpers.ts new file mode 100644 index 00000000000..97ae8ddb86e --- /dev/null +++ b/apps/docs/scripts/helpers.ts @@ -0,0 +1,9 @@ +export const nameMap = { + api: 'Management API', + cli: 'Supabase CLI', + auth: 'Auth Server', + storage: 'Storage Server', + postgres: 'Postgres', + dart: 'Supabase Flutter Library', + javascript: 'Supabase JavaScript Library', +} diff --git a/apps/docs/scripts/tsconfig.json b/apps/docs/scripts/tsconfig.json new file mode 100644 index 00000000000..de1ecb67a32 --- /dev/null +++ b/apps/docs/scripts/tsconfig.json @@ -0,0 +1,15 @@ +// generator files need their own tsconfig.json because they don't like "module": "esnext" setting that nextjs requires in the main tsconfig +{ + "compilerOptions": { + "incremental": true, + "noImplicitAny": false, + "esModuleInterop": true, + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "~/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/apps/docs/styles/algolia-search.scss b/apps/docs/styles/algolia-search.scss index a789f88a5bb..0e2b90589f6 100644 --- a/apps/docs/styles/algolia-search.scss +++ b/apps/docs/styles/algolia-search.scss @@ -81,8 +81,7 @@ --aa-overlay-color-alpha: 0.4; // Shadows - --aa-panel-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1), - 0 6px 16px -4px rgba(35, 38, 59, 0.15); + --aa-panel-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1), 0 6px 16px -4px rgba(35, 38, 59, 0.15); // Scrollbar --aa-scrollbar-width: 13px; @@ -122,8 +121,7 @@ body { --aa-icon-color-rgb: 119, 119, 163; // Shadows - --aa-panel-shadow: inset 1px 1px 0 0 rgb(44, 46, 64), - 0 3px 8px 0 rgb(0, 3, 9); + --aa-panel-shadow: inset 1px 1px 0 0 rgb(44, 46, 64), 0 3px 8px 0 rgb(0, 3, 9); // Scrollbar --aa-scrollbar-track-background-color-rgb: 44, 46, 64; @@ -429,10 +427,7 @@ body { } // Title typography @at-root .aa-SourceHeaderTitle { - background: rgba( - var(--aa-background-color-rgb), - var(--aa-background-color-alpha) - ); + background: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha)); color: rgba(var(--aa-primary-color-rgb), 1); display: inline-block; font-size: 0.8em; @@ -464,8 +459,7 @@ body { rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha)), rgba(128, 126, 163, 0.14) ); - border: 1px solid - rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha)); + border: 1px solid rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha)); border-radius: 5px; box-shadow: inset 0 0 2px #fff, 0 2px 2px -1px rgba(76, 69, 88, 0.15); color: inherit; @@ -502,10 +496,7 @@ body { // The result type icon inlined SVG or image @at-root .aa-ItemIcon { align-items: center; - background: rgba( - var(--aa-background-color-rgb), - var(--aa-background-color-alpha) - ); + background: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha)); border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); @@ -658,10 +649,7 @@ body { opacity: 0.4; } @at-root .aa-ItemContentTag { - background-color: rgba( - var(--aa-primary-color-rgb), - var(--aa-primary-color-alpha) - ); + background-color: rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)); border-radius: 3px; margin: 0 0.4em 0 0; padding: 0.08em 0.3em; @@ -754,10 +742,7 @@ body { // 8. Panel Footer //---------------- .aa-PanelFooter { - background-color: rgba( - var(--aa-background-color-rgb), - var(--aa-background-color-alpha) - ); + background-color: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha)); box-shadow: inset 0 1px 0 rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); display: flex; @@ -847,10 +832,7 @@ body { &:hover, &:focus { box-shadow: inset 0 0 0 1px - rgba( - var(--aa-panel-border-color-rgb), - var(--aa-panel-border-color-alpha) - ); + rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); } } } @@ -969,7 +951,11 @@ body { } // search bar +input[type='search'].DocSearch-Input { + background-color: var(--colors-scale1); +} + .dark .DocSearch-Input { background-color: var(--colors-scale2); color: white; -} \ No newline at end of file +} diff --git a/apps/docs/styles/docsearch.scss b/apps/docs/styles/docsearch.scss index a9ca46569c5..8d0cb5f6cd6 100644 --- a/apps/docs/styles/docsearch.scss +++ b/apps/docs/styles/docsearch.scss @@ -138,7 +138,7 @@ display: none; } -.DocSearch-Cancel { +button[type='reset'].DocSearch-Cancel { appearance: none; flex: none; font-size: 0; @@ -202,7 +202,7 @@ @apply ring-scale-300 bg-white shadow-sm ring-1 dark:bg-slate-700 dark:ring-0; } -.DocSearch-Hit--Parent .DocSearch-Hit-icon { +.DocSearch-Hit--Parent.DocSearch-Hit--Guide .DocSearch-Hit-icon { /* book icon */ background-image: url("data:image/svg+xml,%3Csvg width='14' height='10' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3.5 0c1.093 0 2.117.27 3 .743V10a6.344 6.344 0 0 0-3-.743c-1.093 0-2.617.27-3.5.743V.743C.883.27 2.407 0 3.5 0Z' fill='%23BAE6FD'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.5 0c1.093 0 2.617.27 3.5.743V10c-.883-.473-2.407-.743-3.5-.743s-2.117.27-3 .743V.743a6.344 6.344 0 0 1 3-.743Z' fill='%2338BDF8'/%3E%3C/svg%3E"); } @@ -289,7 +289,11 @@ } .DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-action path { - stroke: white; + stroke: #777; + + .dark & { + stroke: #aaa; + } } .DocSearch-Hit > a { @@ -392,7 +396,7 @@ .DocSearch-StartScreen { .DocSearch-Help { - @apply text-center py-16; + @apply text-center py-16; } } @@ -527,4 +531,4 @@ .DocSearch-Hit-action + .DocSearch-Hit-action { // @apply ml-3 border-l border-slate-200 pl-3 dark:border-slate-200; -} \ No newline at end of file +} diff --git a/apps/www/_alternatives/supabase-vs-firebase.mdx b/apps/www/_alternatives/supabase-vs-firebase.mdx index 96171b30a95..0ae182bebcc 100644 --- a/apps/www/_alternatives/supabase-vs-firebase.mdx +++ b/apps/www/_alternatives/supabase-vs-firebase.mdx @@ -66,4 +66,4 @@ We also have guides and tools for [migrating Firebase Auth to Supabase Auth](htt These are by far the most complete Firebase to Postgres migration tools available anywhere on the web. -You can [try Supabase for free](https://app.supabase.com). If you require Enterprise level support with your project or migration, please get in touch using our [Enterprise contact form](https://supabase.com/contact/enterprise). +You can [try Supabase for free](https://app.supabase.com). If you require Enterprise level support with your project or migration, please get in touch using our [Enterprise contact form](https://forms.supabase.com/enterprise). diff --git a/apps/www/_blog/2021-07-02-supabase-beta-june-2021.mdx b/apps/www/_blog/2021-07-02-supabase-beta-june-2021.mdx index 80ca73046d1..2d4e0ca9bde 100644 --- a/apps/www/_blog/2021-07-02-supabase-beta-june-2021.mdx +++ b/apps/www/_blog/2021-07-02-supabase-beta-june-2021.mdx @@ -57,13 +57,13 @@ Ever wanted to build a Search Engine? We just released a guide which shows you h ### OAuth Guides We released step-by-step guides to help you set up OAuth with -[Apple](/docs/guides/auth/auth-apple), -[Bitbucket](/docs/guides/auth/auth-bitbucket), -[Facebook](/docs/guides/auth/auth-facebook), -[GitHub](/docs/guides/auth/auth-github), -[GitLab](/docs/guides/auth/auth-gitlab), -[Google](/docs/guides/auth/auth-google), and -[Twitter](/docs/guides/auth/auth-twitter). +[Apple](/docs/guides/auth/social-login/auth-apple), +[Bitbucket](/docs/guides/auth/social-login/auth-bitbucket), +[Facebook](/docs/guides/auth/social-login/auth-facebook), +[GitHub](/docs/guides/auth/social-login/auth-github), +[GitLab](/docs/guides/auth/social-login/auth-gitlab), +[Google](/docs/guides/auth/social-login/auth-google), and +[Twitter](/docs/guides/auth/social-login/auth-twitter). ![Image of Apple's developer Portal](/images/blog/2021-june/apple-developer-portal.png) diff --git a/apps/www/_blog/2021-07-22-supabase-launch-week-sql.mdx b/apps/www/_blog/2021-07-22-supabase-launch-week-sql.mdx index f86c57ea758..edef105d6df 100644 --- a/apps/www/_blog/2021-07-22-supabase-launch-week-sql.mdx +++ b/apps/www/_blog/2021-07-22-supabase-launch-week-sql.mdx @@ -63,7 +63,7 @@ Wednesday 28 July 2021.[^1] ### What? -What's cooler than Arnie in the 90's? Passwordless logins. We've [already](/docs/guides/auth/auth-apple) [built](/docs/guides/auth/auth-bitbucket) [support](/docs/guides/auth/auth-discord) [for](/docs/guides/auth/auth-facebook) [eight](/docs/guides/auth/auth-github) [different](/docs/guides/auth/auth-gitlab) [Oauth](/docs/guides/auth/auth-google) [providers](/docs/guides/auth/auth-twitter), so it's anyone's guess what can happen in Supabase Auth Episode II. +What's cooler than Arnie in the 90's? Passwordless logins. We've [already](/docs/guides/auth/social-login/auth-apple) [built](/docs/guides/auth/social-login/auth-bitbucket) [support](/docs/guides/auth/social-login/auth-discord) [for](/docs/guides/auth/social-login/auth-facebook) [eight](/docs/guides/auth/social-login/auth-github) [different](/docs/guides/auth/social-login/auth-gitlab) [Oauth](/docs/guides/auth/social-login/auth-google) [providers](/docs/guides/auth/social-login/auth-twitter), so it's anyone's guess what can happen in Supabase Auth Episode II. ### Where? diff --git a/apps/www/_blog/2021-07-28-supabase-auth-passwordless-sms-login.mdx b/apps/www/_blog/2021-07-28-supabase-auth-passwordless-sms-login.mdx index aa7a26ca013..92623917793 100644 --- a/apps/www/_blog/2021-07-28-supabase-auth-passwordless-sms-login.mdx +++ b/apps/www/_blog/2021-07-28-supabase-auth-passwordless-sms-login.mdx @@ -51,7 +51,7 @@ with either an OTP or a phone + password combo. Supabase Auth supports [Twilio](https://www.twilio.com/) as an SMS provider, with more options coming soon. Simply plug your Twilio credentials into your Auth Settings in the Supabase Dashboard to get started. -Check out the [documentation](/docs/guides/auth/auth-twilio) to get started with Mobile OTPs, +Check out the [documentation](/docs/guides/auth/phone-login/twilio) to get started with Mobile OTPs, or watch the [Youtube guide](https://youtu.be/akScoPO01bc). ## What is MFA? @@ -124,3 +127,11 @@ Be mindful of your user’s preference, though. If a user has enabled MFA, they For starters, we are looking to support WebAuthn and FIDO2 compliant devices such as Yubikeys. We also hope to allow users to receive email notifications when selected MFA actions are triggered. If you have MFA requirements which are not covered here feel free to write to us at support[at]supabase.io . We are grateful to our early MFA users for the support and feedback provided throughout this period. In particular, we would like to thank [Fabian Beer](https://madebyfabian.com), [Cogram](https://www.cogram.com), and [Happl](https://happl.com) whose detailed feedback helped to shape our implementation. We would also like to specially thank the community behind the [pquerna/otp](https://github.com/pquerna/otp) and [ajstarks/svgo](https://github.com/ajstarks/svgo) libraries - their work is indispensable to this implementation. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx b/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx new file mode 100644 index 00000000000..c746fd61ba4 --- /dev/null +++ b/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx @@ -0,0 +1,264 @@ +--- +title: 'Supabase Wrappers, a Postgres FDW framework written in Rust' +description: 'A framework for building Postgres Foreign Data Wrappers which connects to Stripe, Firebase, Clickhouse, and more.' +author: paul_copplestone,bo_lu,oli_rice +image: launch-week-6/wrappers/wrappers-og.png +thumb: launch-week-6/wrappers/wrappers-og.png +tags: + - launch-week +date: '2022-12-15' +toc_depth: 3 +--- + +Today we're releasing [Supabase Wrappers](https://github.com/supabase/wrappers), a framework for building Postgres Foreign Data Wrappers (FDW) which connects Postgres to external systems. + +Foreign Data Wrappers are a core feature of PostgreSQL. We've extended this feature to query other databases or any other external system (including third-party APIs), using SQL. + +![FDW](/images/blog/launch-week-6/wrappers/fdw-database.png) + +We're releasing Wrappers today in Alpha, with support for [Firebase](https://supabase.github.io/wrappers/firebase/) and [Stripe](https://supabase.github.io/wrappers/stripe/). Wrappers for Clickhouse, BigQuery, and Airtable are under development. + +## Example with Stripe + +Let's step through a full example using the Stripe Wrapper. + +![FDW](/images/blog/launch-week-6/wrappers/stripe-fdw.png) + +### Connecting to Stripe + +First, let's give your Postgres database some authentication details to access your Stripe account: + +```sql +create server stripe_server +foreign data wrapper stripe_wrapper +options (api_key 'sk_test_xxx'); +``` + +### Creating a Foreign Table + +Now we can map your Stripe data to Foreign Tables, which are just like normal tables except that the data exists _outside_ of your database. + +```sql +-- Create a foreign table for your Stripe products +create foreign table products ( + id text, + name text, + description text, + default_price text +) +server my_stripe_server +options ( object 'products' ); +``` + +### Accessing remote data + +After setting up your foreign table, you can query you Stripe products directly from your database: + +```sql +-- Fetch all your stripe products in Postgres +select * +from products +limit 10; +``` + +![Stripe Products](/images/blog/launch-week-6/wrappers/stripe-data.png) + +Or from your application, using one of our client libraries: + +```jsx +import { createClient } from '@supabase/supabase-js' + +const SUPABASE_URL = 'https://xyzcompany.supabase.co' +const SUPABASE_KEY = 'public-anon-key' + +const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) + +const { data: stripeCustomers, error } = supabase + .from('products') + .select('id, name, description, default_price') + .limit(10) +``` + +_Note: we kept this example simple, however for API security and code organization, you should store your foreign data in a [separate schema](/docs/reference/javascript/initializing#api-schemas)._ + +## Use cases + +Once we've added more Wrappers, they enable various possibilities: + +- **On-demand Big Data:** Query your Data Warehouse on demand using Wrappers for Clickhouse, BigQuery, Snowflake, Oracle, and S3. +- **Simplified Onboarding:** Migrate to Postgres from systems like Firebase, MySQL, and Airtable. +- **Simplified Development:** Create a new Stripe customer object within a Postgres function. +- **AI capabilities:** Run AI queries from your database using OpenAI's API. +- **Caching:** use Postgres triggers to insert data into in-memory databases like Redis. +- **SRE and DevOps:** Query your infrastructure state, like AWS and DNS records. +- **Web3 Apps:** integrate with IPFS and blockchains like Ethereum. +- **Financial Apps:** Build Financial applications using wrappers around Finance APIs. +- **Community analytics:** Analyze your community engagement with GitHub, Slack, Discord, and Twitter wrappers. + +## On-demand ETL + +In their 2017 [paper](https://www.sciencedirect.com/science/article/abs/pii/S0169023X1730438X), researchers from the University of Bologna investigated an approach to on-demand ETL: + +> In traditional OLAP systems, the ETL process loads all available data in the data warehouse before users start querying them. In some cases, this may be either inconvenient (because data are supplied from a provider for a fee) or unfeasible (because of their size); on the other hand, directly launching each analysis query on source data would not enable data reuse, leading to poor performance and high costs. The alternative investigated in this paper is that of fetching and storing data on-demand. + +Their paper outlines the foundation for QETL (pronounced "kettle"): Query, Extract, Transform, Load. This differs from a more traditional ETL/ELT approach, where data is moved from one place to another. In QETL, the “Query” function allows data engineers to access data in a remote system even before moving it. This approach reduces the reliance on data engineering infrastructure, allowing teams to access operational insights faster. + +### The benefits of QETL + +We've built upon this concept using PostgreSQL's FDW system. This a new tool for developers and data engineers, with several benefits: + +1. **Simplicity:** the Wrappers API is just SQL, so data engineers don't need to learn new tools and languages. +2. **On-demand:** analytical data is available within your product without any additional infrastructure, and the time it takes to retrieve that data is close to executing a query on the source. +3. **Always in sync:** data which isn't moved will always be in sync. Developers can set up local views which re-map remote data into clean local schemas. +4. **Integrated:** large datasets are available within your application, and can be joined with your operational/transactional data. +5. **Save on bandwidth:** only extract/load what you need. +6. **Save on time:** avoid setting up additional data pipelines. +7. **Save on Data Engineering costs:** less infrastructure to be managed. + +### QETL + Postgres + +How does this look in action? Assuming that all of your analytical data is stored in Snowflake, you could create a foreign table inside your Supabase database: + +```sql +create foreign table snowflake.order_history ( + id bigint, + ts timestamptz, + event text, + user_id uuid +) +server my_snowflake_warehouse +options (table 'order_history', rowid_column 'id'); +``` + +Now from your Supabase database you can query your Snowflake data directly: + +```sql +select * from snowflake.order_history limit 1000; +``` + +You can even join remote data with your local tables to enrich existing operational data. For example, to figure out how many times a user has purchased something from your store: + +```sql +select + users.id, + count(order_history.event) +from + snowflake.order_history +join + auth.users on auth.users.id = snowflake.order_history.user_id +where + order_history.event = 'purchase' and + order_history.user_id = ''; +``` + +We can either run these queries on demand or, for better query performance, we can run them in the background (using something like [pg_cron](https://supabase.com/docs/guides/database/extensions/pgcron)), and materialize the data into a local table. + +![QETL](/images/blog/launch-week-6/wrappers/qetl.png) + +This gives us the basis of QETL: + +- Query: run on-demand SQL queries, directly from your Postgres database. +- Extract: run SQL `select` statements on external systems, either on demand or on a recurring basis. +- Transform: use SQL aggregations and CTEs to transform the data. +- Load: store transformed data into local tables for faster access. + +This is a two-way process. It's equally useful to offload large datasets from your Postgres database to your Data Warehouse. With FDWs, this can be as simple as: + +```sql +insert into snowflake.analytics +select * from analytics +where ts > (now() - interval '1 DAY'); +``` + +On-demand ETL is a strong compliment for current ETL practices, and another tool in the toolbelt for Data Engineering and Developers that works with immediately with tools that interface with Postgres. + +## Postgres, the everything interface + +In a recent Software Engineering [episode](https://podcasts.apple.com/us/podcast/software-engineering-daily/id1019576853?i=1000580384354) Andy Pavlo (database Professor at Carnegie Mellon and Co-Founder of OtterTune), explored the future between “better databases” and “better interfaces” [00:37:18]: + + + +Specialized engines are always going to outperform general-purpose ones. The question is whether +the specialized engine is going to have such a significant difference in performance that it can +overcome the limitations of a general purpose one. + +... + +The challenge oftentimes is this: is the benefit you're getting from a specialized engine +because the _Engine_ is different or the _API_ is different?. + + + +He goes on to explore the benefits of a Graph database vs a Relational database. + +Our recent release of [pg_graphql](https://github.com/supabase/pg_graphql/) closes the gap on the graph use-case by building a GraphQL API directly into Postgres as an extension. While a specialized graph database might provide performance benefits over Postgres, perhaps one of the largest benefits is simply the Graph API which makes it easier to reason about the data. + +With the introduction of Wrappers, we're hoping to close the gap on even more of these type of workloads. + +An exciting part of the FDW approach is that it provides a common interface to the world: SQL. While it has many shortcomings, SQL is the lingua franca of data. Postgres' FDWs transform any API into a data set with a common interface. This “interface aggregator” is similar to the [promise](https://medium.com/vicetech/graphql-the-great-aggregator-bcf52fe390d9) of GraphQL engines. The benefit of embedding this functionality in the database is that it exists at the _lowest level of the tech stack_. Everything that is built on top can leverage it. While Postgres cannot easily access the functionality of a GraphQL server, a GraphQL server can easily access the functionality of Postgres. + +The FDW interface also future-proofs Postgres. Instead of keeping up with the latest technological advances, Postgres can instead act as an interface whenever they develop. The recent advance in AI and ML is a great example of this: AI technology is developing faster than the time it would take to build a new “AI database”. With a FDW, Postgres can become the interface to this technology and many other technological advances in the future. + +## Developing Wrappers + +Postgres has a builtin “Postgres FDW” allows querying one Postgres database from another. We've extended this functionality to support a variety of data sources, from Data Warehouses to APIs. +This release includes two initial wrappers: Stripe and Firebase + +| Integration | Platform | Self-hosted | select | insert | update | delete | +| ----------- | -------- | ----------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | +| Firebase | 🚧 | ✅ | ✅ | 🚧 | 🚧 | 🚧 | +| Postgres | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| Stripe | 🚧 | ✅ | ✅ | 🚧 | 🚧 | 🚧 | + +With several more [under development](https://github.com/supabase/wrappers/tree/main/wrappers/src/fdw): + +| Integration | select | insert | update | delete | +| ----------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | +| Airtable | ✅ | 🚧 | 🚧 | 🚧 | +| BigQuery | ✅ | ✅ | ✅ | ✅ | +| ClickHouse | ✅ | ✅ | ✅ | ✅ | + +Wrappers used [pgx](https://github.com/tcdi/pgx), extending it with FDW support. pgx is a Postgres extension framework written in Rust. Wrappers is very similar to [Steampipe](https://steampipe.io/) or [Multicorn](https://multicorn.org/). We opted to develop our own framework for several reasons: + +- The current state of FDWs is in disarray. It's hard to know which FDWs are supported and functional. We think there's a benefit to colocating all FDWs in a single repository using modern tooling. This makes contributing simpler and maintenance faster. +- Wrappers has async support, which enables the development of RESTful API-based FDWs, like Stripe. +- It's written in Rust, which provides reliable performance, strong typing, data security, and “push down” is supported through the framework. + +## Supported types and Push Down + +Wrappers [supports](https://github.com/supabase/wrappers/blob/83887dcc2ddcf972ca1b1eec4a598cd7bff947de/supabase-wrappers/src/interface.rs#L11) a variety of types, including: +`bool`, `i8`, `i16`, `f32`, `i32`, `f64`, `i64`, `String`, `Date`, `Timestamp`, and `JsonB`. + +Foreign Data Wrappers have a concept of "push down". This means that the FDW runs the query on _remote_ data source. This is useful for performance reasons, as the remote data source can often perform the query more efficiently than Postgres. Push down is also useful for security reasons, as the remote data source can enforce access control. Limited push-down support has been added as a Proof of Concept, but this will be a key focus of Wrappers. + +You can follow development of all the Wrappers in the official [GitHub Repo](https://github.com/supabase/wrappers). + +## Next Steps + +We're not "officially" releasing Wrappers onto the platform yet, although the brave and curious might be able to figure out how to use it "unofficially". Caveat emptor: there will be breaking changes. + +We're excited to see what the community does with Wrappers. We're hoping that Wrappers will help to accelerate the adoption of Postgres as a data hub. +If you're interested in getting involved or building your own Wrapper, don't hesitate to jump into the code and start developing with us. + +- Star & Watch the GitHub repo: [github.com/supabase/wrappers](https://github.com/supabase/wrappers) +- View the documentation: [supabase.github.io/wrappers](https://supabase.github.io/wrappers/) +- Supabase Launch Week: [supabase.com/launch-week](https://supabase.com/launch-week) + + + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/_blog/2022-12-16-custom-domain-names.mdx b/apps/www/_blog/2022-12-16-custom-domain-names.mdx new file mode 100644 index 00000000000..014255f71a8 --- /dev/null +++ b/apps/www/_blog/2022-12-16-custom-domain-names.mdx @@ -0,0 +1,67 @@ +--- +title: Custom Domain Names +description: Change your Supabase project's domain name to your own domain. +author: div_arora +image: launch-week-6/custom-domains/og-custom-domains.png +thumb: launch-week-6/custom-domains/og-custom-domains.png +tags: + - launch-week +date: '2022-12-16' +toc_depth: 3 +--- + +After your side-project becomes wildly viral, and you've graduated into a “serious business”, delivering a more branded experience is probably one of the items at the bottom of your checklist. + +To that end, we're releasing custom domains, and vanity subdomains, to help you present a more polished product to your users. + +# Custom Domains + +Custom domains allow you to use your own domain for your Supabase project. + +Instead of seeing: + +`sqvfdnkeiuztnsinmtau.supabase.co` + +your users instead interact with + +`api.example.com`: + +![FDW](/images/blog/launch-week-6/custom-domains/custom-subdomain.png) + +Today, we're making Custom Domains generally available, and they're now accessible as a paid add-on through the Supabase dashboard. + +Get your custom domain in the [Dashboard](https://app.supabase.com/project/_/settings/general) + +# Vanity Subdomains + +Vanity Subdomains allow you to choose a subdomain on Supabase's own domain. + +Instead of hosting your services on a randomly assigned subdomain: + +`abcdefghijklmno.supabase.co` + +you can choose one that's relevant to your project, for example: + +`my-example-brand.supabase.co` + +Vanity Subdomains are offered at no additional cost for all projects on a paid plan, and are being launched in a closed beta. + +Instructions for setting up Vanity Subdomains are now available in our [docs](https://supabase.com/docs/guides/platform/custom-domains#vanity-subdomains). + +## Limitations + +In this release, we still have some limitations that we're working through: + +1. Edge Functions don't support custom domains or vanity subdomains yet, so you have to use the current endpoint to access them. +2. Right now, you can only set up one custom domain or vanity subdomain per project. + +We're working hard to fix these limitations, so stay tuned for future updates. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx b/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx new file mode 100644 index 00000000000..7e84894bfb6 --- /dev/null +++ b/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx @@ -0,0 +1,240 @@ +--- +title: 'Community Day' +description: Wrapping up Launch Week 6 with contributors, partners, and friends. +author: andrew_smith,jonmeyers_io,thor_schaeff,tyler_shukert +image: lw6-community/community-day.png +thumb: lw6-community/community-day.png +tags: + - launch-week + - community +date: '2022-12-16' +toc_depth: 3 +--- + +Supabase is a collaborative company. We work with, sponsor, and support as many open source tools as possible. The great thing about this approach is that each tool brings their own community and it's starting to feel like Supabase is really just a “community of communities”. Far too much has happened in the Supabase community in the last 3 months for us to possibly feature it all here, so here's a collection of the highlights! + +## New Integrations + +While we've been working hard on new features, the community has been developing a healthy [integrations marketplace](https://supabase.com/docs/guides/integrations/integrations). Since Supabase is just Postgres, any tool which works with Postgres works with Supabase (no additional changes required). Today we're adding a few major players to the roster: + +### FlutterFlow + + + +[FlutterFlow](https://flutterflow.io/) is a low-code builder for developing native mobile applications using Flutter. You can use the simple drag-and-drop interface to build your app faster than traditional development. + +An integration between FlutterFlow and Supabase has been long awaited by the community. Starting today, you can build your apps with FlutterFlow and use Supabase for your backend! + +This is just the beginning of our integration with FlutterFlow. We're working closely with the FlutterFlow team to deliver more features! + +Watch John from the FlutterFlow team demonstrate how you can [get started with FlutterFlow and Supabase](https://youtu.be/TmViZsWEBY0). + +### OneSignal + + + +[OneSignal](https://onesignal.com/) is a messaging platform allowing you to deliver push notifications, in-app messages, SMS, and emails to your users. + +Combining OneSignal with Supabase, you can send cloud messages to your users with any database change. + +We have guides on how to get started with [Next.js and OneSignal](https://supabase.com/docs/guides/integrations/onesignal), and [Flutter and OneSignal](https://github.com/OneSignalDevelopers/onesignal-supabase-sample-integration-supabase). + +In the video above, William from OneSignal will show you how you can easily integrate OneSignal with your Supabase app. + +### NextAuth + + + +[NextAuth.js](https://next-auth.js.org/) is an open source authentication solution for [Next.js](https://nextjs.org/). It allows you to bring your own Database so that you own your user data. + +The amazing NextAuth community who have built a [Supabase Adapter](https://next-auth.js.org/adapters/supabase) that makes it easy to use NextAuth.js with Supabase, and enables the use of [Row Level Security (RLS) policies](https://next-auth.js.org/adapters/supabase#enabling-row-level-security-rls). + +In [this community spotlight video](https://youtube.com/EdYQ9fF-hz4), [Thang Huu Vu](https://twitter.com/thanghvu), the lead maintainer of NextAuth.js, gives an overview and brief history of NextAuth, followed by a tutorial on how to set up the new Supabase Adapter. + +## Postgres Ecosystem + +### PGroonga Multilingual Search extension + +![PGroonga](/images/blog/lw6-community/pgroonga.jpg) + +Over the past few years, we've had a number of people ask if we can add Full Text Search for other languages. PGroonga has been on our radar for a long time now, so when we reached out to them we were surprised to learn that _no_ Postgres platform currently supports them. Today we're fixing this by becoming the first. + +PostgreSQL of course features excellent [Full Text Search](https://supabase.com/docs/guides/database/full-text-search) out-the-box, but it can be lacking if you need to search against languages with non-Roman characters such as Japanese, Chinese and so on. For this you can use the PGroonga extension! It's already installed on all new projects, just head to the [Database tab](https://app.supabase.com/project/_/database/extensions) on the dashboard and search or scroll for 'PGroonga' and hit enable to get started. Once enabled you can head to [their excellent documentation](https://pgroonga.github.io/tutorial/) on how to start making queries. + +PGroonga is backed by a collection of incredible maintainers, contributors, and a broad and diverse [community](https://pgroonga.github.io/community/). + +### PostgreSQL 15 + +![PG15](/images/blog/lw6-community/pg15.png) + +The PostgreSQL community [released](https://www.postgresql.org/docs/current/release-15.html) version 15 (stable) in October 2022. All Projects created on the Supabase platform from today will be on version 15. If you want to upgrade one of your existing Projects, check out our [Upgrading](https://supabase.com/docs/guides/platform/migrating-and-upgrading-projects#upgrade-your-project) documentation, and if you want to see what's new, check out : XXX + +Read [what's new in **Postgres 15?**](https://supabase.com/blog/new-in-postgres-15) + +### PostgREST version 11 pre-release + +![Postgrest 11](/images/blog/lw6-community/postgrest.png) + +PostgREST 11 is not wrapped up yet but you can try a pre-release locally with the Supabase CLI. Some of the new features include: spreading related tables, related orders and anti-joins. Read on more about these on: + +[Learn more about PostgREST 11](https://supabase.com/blog/postgrest-11-prerelease) + +## Made with Supabase + +![Made With Supabase](/images/blog/lw6-community/made.jpg) + +Perhaps you've seen [madewithsupabase.com](https://www.madewithsupabase.com/), but did you know that the site was made and is maintained by an [open source contributor](https://twitter.com/zernonia) (during our first hackathon)? Since then, there have been over 300 apps and websites listed. Here's some of our favourites: + +### LottieFiles + +LottieFiles built a [Mobile Motion Canvas](https://www.youtube.com/watch?v=QoN7l_Wq_S4) where you can create and share social stories, posts, stickers, & more. + +### Mobbin + +Mobbin use Supabase Auth to power their [UI/UX library of Mobile and Web screenshots](https://mobbin.com/browse/ios/apps). Last year they [migrated 200k users from Firebase to Supabase Auth](https://supabase.com/blog/mobbin-supabase-200000-users). + +### sound.xyz + +[sound.xyz](https://sound.xyz) is platform for artists to drop tracks to their fans first, users support the artists they love directly and stake their claim on being there before everyone else. + +### Topaz + +[Topaz](https://topaz.network/) is one of the fastest growing NFT networks and chose supabase as a backend to ensure they won't lose customers during peak traffic periods. + +### Repeat.dev + +[Repeat.dev](https://repeat.dev) is a platform for webhook based task automation. It has a built in scheduler, and can handle emails and pdf generation. + +### Dots + +[Dots](https://www.dots.community/) is a tool for interactive onboarding and support flows across Slack and Discord. Dots uses Supabase so they don't have to worry about managing a backend, and can focus on helping their users build amazing community experiences. + +### Fleeting Notes + +[Fleeting Notes](https://www.fleetingnotes.app/) allows you to take linked notes within your browser or on your phone, then sync the notes with Obsidian. They wrote an awesome guide on how they [migrated 1000+ users from Firebase to Supabase](https://fleetingnotes.app/posts/migrating-from-firebase-to-supabase/). + +## Content Creators + +![Content Creators](/images/blog/lw6-community/content-storm.png) + +One of the most exciting developments this year is the number of content creators and developers helping _others_ to get started with Supabase. Ultimately, this means more developers using Postgres. There's really too many of these awesome folks to feature, but here's a few who have gone above and beyond: + +### Content Storm + +More than 30+ creators featured in our [Content Storm](https://supabase.com/blog/the-supabase-content-storm). These folks all produced brand new content in the build up to Launch Week and dropped it simultaneously! + +### Supaship + +![Content Creators](/images/blog/lw6-community/supaship.jpg) + +Supaship built a whole [Supabase course](https://supaship.io/). It's absolutely jam-packed with advice on how to get the most out of Supabase (and his meme game is absolute fire!). + +### Jon Meyers for Egghead + +![Content Creators](/images/blog/lw6-community/egghead.jpg) + +Check out Jon's brand new, entirely free course on egghead to learn all about the Supabase Auth Helpers. Throughout the course, you will build a realtime chat application with Remix and learn how to: + +- use Supabase server-side in loaders and actions +- query and mutate data as an authenticated user with Supabase +- sign users in with GitHub OAuth +- enforce authorization with Row Level Security (RLS) policies +- merge client and server state with realtime events +- deploy a Remix app to Vercel + +[Build a Realtime Chat App with Remix and Supabase](https://egghead.io/courses/build-a-realtime-chat-app-with-remix-and-supabase-d36e2618) + +### Everything Svelte + +![Content Creators](/images/blog/lw6-community/svelte.jpg) + +[Everything Svelte](https://www.everythingsvelte.com/) is a Sveltekit and Supabase course by [Amy](https://twitter.com/selfteachme). You'll learn everything you need to know to build a modern web application. + +> In Everything Svelte, participants will learn EVERYTHING they need to know to build a full-stack application in SvelteKit and Supabase. We cover topics such as Tailwind styles, Svelte animations and transitions, search, testing, creating components, managing state, Stripe integration, sending emails, GitHub Actions, database modeling, and deployment. Supabase, in particular, really shines as we leverage its authentication system, row level security, local storage, and database APIs. + +## Getting started templates + +### Base Jump + +[usebasejump.com](https://usebasejump.com/) is "The fastest way to launch Supabase apps with NextJS". Basejump is open source. Contributions are both awesome and encouraged! + +### supastarter + +[supastarter.dev](https://supastarter.dev/) is the SaaS starter template for Next.js and Supabase. Save time and focus on your business with this scalable and production-ready starter template for your SaaS. It includes authentication, i18n, subscriptions, landing page and much more! + +## Community libraries + +![Community org](/images/blog/lw6-community/eyes.jpg) + +The Supabase-Community org is home to 80(!) repos built and maintained by the community. It houses everything from [Client Libraries](https://github.com/supabase-community/#client-libraries), to [Auth Helpers](https://github.com/supabase-community/#supabase-auth-helpers), [Self Hosting tooling](https://github.com/supabase-community/#self-hosting), and [Utilities](https://github.com/supabase-community/#utilities). + +An awesome recent addition from the AWS team is [supabase-on-aws](https://github.com/supabase-community/supabase-on-aws), a self-hosting starter kit for AWS. + +## Community Growth + +![Community Growth Chart](/images/blog/lw6-community/graph.jpg) + +At the start of this year [@kiwicopple tweeted](https://twitter.com/kiwicopple/status/1478338320346267648) how far we had come as a community. Since then we've grown to one of the [most popular](https://github.com/search?q=stars%3A%3E42000&type=repositories) repos on GitHub (top 220) and have grown by: + +- GitHub stars: 25K → 60K (across all repos) +- Hosted Databases: 75K → 250K +- Contributors: 271 → 750 (across all repos) +- Launch Weeks: 3 → 6 +- Discord: 0 → 11k + +## Giving back + +At less than 3 years old we're still finding our feet, but one of the things we're most proud of is our contribution back to open source. Technically everyone working at Supabase is an open source contributor, so it's hard to quantify exactly the value we've been contributing to the open source ecosystem. To name a few of the more obvious ways: + +- Paid out over $100,000 to contributors via [Open Collective](https://opencollective.com/supabase). +- Invested in $500,000 into [OrioleDB](https://github.com/orioledb/orioledb) to accelerate the Table Access API in Postgres. +- We financially sponsor open source tools, like [PostgREST](https://opencollective.com/supabase-postgrest) and [PGroonga](https://opencollective.com/clear-code), and research initiatives like [Elixir type system](https://twitter.com/josevalim/status/1535008937640181760?s=20&t=BLqeO2YpdhYfCZxgsmlNug). +- We employ maintainers of the external tools which we use, including PostgREST and pgsodium (to work on those tools)! +- Our team has contributed several patches to the Postgres core. +- We help to drive open source adoption on tools like [Deno](https://deno.land/). +- We collaborated with the [Snaplet](https://www.snaplet.dev/) team to develop and open source [Postgres WASM](https://supabase.com/blog/postgres-wasm). +- And possibly the biggest: we've maintained our OSI-compliant stance. With the exception of some of our cloud-infra & billing code, the Supabase ecosystem is all MIT, Apache 2.0, or PostgreSQL licensed. + +We plan to continue our open and collaborative trend. There are many companies working on exciting ideas in the database ecosystem, and there are far too many problems for the Supabase team to solve alone. If you're interested in working with us to solve these problems, don't ever hesitate to reach out. + +## Getting involved + +- Want to contribute? Dive into any of our [repos](https://github.com/supabase/) to get started. +- Want to work in open source? We don't have many openings today, but keep this URL in mind in the future when you're job-hunting: [supabase.com/careers](https://supabase.com/careers) +- Want to try out Supabase? [Join the Hackathon](https://supabase.com/blog/launch-week-6-hackathon) and win some nice prizes. +- Want to support us? Just a [GitHub star](https://github.com/supabase/supabase) is enough ⭐. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) diff --git a/apps/www/_blog/2022-12-16-launch-week-6-wrap-up.mdx b/apps/www/_blog/2022-12-16-launch-week-6-wrap-up.mdx new file mode 100644 index 00000000000..1e25e3c1534 --- /dev/null +++ b/apps/www/_blog/2022-12-16-launch-week-6-wrap-up.mdx @@ -0,0 +1,207 @@ +--- +title: 'Launch Week 6: Wrap Up' +description: "That's a wrap on Supabase Launch Week Day 6. Here's everything we shipped in one long blog post." +author: paul_copplestone +image: launch-week-6/wrap-up/og-wrap-up.png +thumb: launch-week-6/wrap-up/og-wrap-up.png +tags: + - launch-week +date: '2022-12-16' +toc_depth: 3 +--- + +That's a wrap on Supabase Launch Week Day 6. Here's everything we shipped in one long blog post. + +## New Docs, built with Next.js + +![New Docs, built with Next.js](/images/blog/lw6-day-1/lw6-day1-docs.jpg) + +Monday + +For a developer tool, documentation is more than a resource - it's part of the product. For the past two years at Supabase, this part of our product hasn't been great. Our new docs, built with Next.js, feature a completely new design, better navigation, and the promise of a fully-integrated experience. + +- Read the [announcememt](/blog/new-supabase-docs-built-with-nextjs) +- Watch the [recap on YouTube](https://www.youtube.com/watch?v=Q1Amk6iDlF8) +- Check out [the new docs](https://supabase.com/docs) + +## Storage v2: Image resizing and Smart CDN + +![Storage v2: Image resizing and Smart CDN](/images/blog/lw6-storage/Image-resizing.jpg) + +Tuesday + +We're introducing three new features for Supabase Storage: Image resizing, webhooks, and a Smart CDN. These features are designed to work together to deliver a next-gen image resizing system. + +- Read the [announcement](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- Watch the [recap on YouTube](https://www.youtube.com/watch?v=NpEl20iuOtg) +- Browse the docs for [Image Transformations](https://supabase.com/docs/guides/storage/image-transformations) +- Browse the docs for our [Smart CDN](https://supabase.com/docs/guides/storage/cdn#smart-cdn-caching) +- Discuss it on [HackerNews](https://news.ycombinator.com/item?id=33969076) + +## Auth: Multi-factor Authentication with RLS + +![Auth: Multi-factor Authentication with RLS](/images/blog/lw6-auth/mfa-banner.jpg) + +Wednesday + +We released Multi Factor Authentication for you to build more secure applications. We built a unique twist so that you can use MFA within your Row Level Security Policies. + +- Read the [announcement](/blog/mfa-auth-via-rls) +- Watch the [recap on YouTube](https://www.youtube.com/watch?v=He7LI2mv9v0) +- Browse the [docs](/docs/guides/auth/auth-mfa) +- Discuss it on [HackerNews](https://news.ycombinator.com/item?id=33984104) + +## Wrappers, a FDW framework for Postgres + +![Wrappers, a FDW framework for Postgres](/images/blog/launch-week-6/wrappers/wrappers-og.png) + +Thursday + +We announced [Supabase Wrappers](https://github.com/supabase/wrappers), a framework for building Postgres Foreign Data Wrappers (FDW) which connects Postgres to external systems. We're releasing Wrappers today in Alpha, with support for Firebase and Stripe. Wrappers for Clickhouse, BigQuery, and Airtable are under development. + +- Read the [announcement](/blog/postgres-foreign-data-wrappers-rust) +- Watch the [recap on YouTube](https://www.youtube.com/watch?v=He7LI2mv9v0) +- Browse the [docs](https://supabase.github.io) +- Discuss it on [HackerNews](https://news.ycombinator.com/item?id=34001493) + +## Vault: secrets and encryption in Postgres + +![Vault: secrets and encryption in Postgres](/images/blog/launch-week-6/vault/og-vault.png) + +Friday + +Vault is a new Postgres extension and accompanying Supabase UI that makes it safe and easy to store encrypted secrets and encrypt other stored data in your database. We're releasing it progressively across the platform and you can expect to see it appear in the Supabase Dashboard in the coming weeks. + +- Read the [announcement](/blog/vault-now-in-beta) +- Learn about [Transparent Column Encryption](/blog/transparent-column-encryption-with-postgres) + +## pg_graphql v1: GraphQL in Postgres + +![pg_graphql v1: GraphQL in Postgres](/images/blog/launch-week-6/pggraphql/og-pg-graphql.png) + +One more thing + +Today released pg_graphql 1.0 release and its general availability on our platform. pg_graphql is a PostgreSQL extension that allows you to query your database using GraphQL. It is the foundation of GraphQL support in the Supabase stack. + +- Read the [announcement](/blog/pg-graphql-v1) +- Browse the [GitHub repo](https://github.com/supabase/pg_graphql/) +- View the [docs](/docs/guides/api#graphql-api) + +## Postgres Point-in-Time Recovery + +![FDW](/images/blog/launch-week-6/pitr/og-pitr.png) + +One more thing + +Point In Time Recovery (PITR) is now enabled from the dashboard for Pro Projects. With PITR, you can restore your database at any specified time in the past. + +- Read the [announcement](/blog/postgres-point-in-time-recovery) +- Review the [Production Readiness docs](/docs/guides/platform/going-into-prod) + +## Custom domains + +![FDW](/images/blog/launch-week-6/custom-domains/og-custom-domains.png) + +One more thing + +Custom domains allow you to use your own domain for your Supabase project. We've released custom domains as an upgrade option for all projects, and vanity domains for Pro projects. + +- Read the [announcement](/blog/custom-domain-names) +- Visit the [Custom Domains docs](/docs/guides/platform/custom-domains) + +## pg_crdt: a Postgres extension for CRDTs + +![pg_crdt: a Postgres extension for CRDTs](/images/blog/launch-week-6/crdt/og-pg-crdt.png) + +One more thing + +We open-sourced an experimental extension for CRDTs, pg_crdt. If you're familiar with Yjs or Automerge, then check out the work we're doing here. It's a PostgreSQL extension that allows you to use CRDTs in your database. + +- Read the [announcement](/blog/postgres-crdt) +- Browse the [GitHub repo](https://github.com/supabase/pg_crdt) +- Discuss it on [HackerNews](https://news.ycombinator.com/item?id=33931971) + +## PostgreSQL 15: we support it + +![PostgreSQL 15: we support it](/images/blog/lw6-community/pg15.png) + +One more thing + +All new projects created on the Supabase platform are now on version 15. The PostgreSQL community released version 15 (stable) in October 2022. + +- Learn what's [new in PostgreSQL 15](/blog/new-in-postgres-15) +- View the full PostgreSQL 15 [release notes](https://www.postgresql.org/docs/15/release-15.html) + +## PostgREST 11: pre-release + +![PostgREST 11: pre-release](/images/blog/lw6-community/postgrest.png) + +One more thing + +You can now test the PostgREST 11 pre-release locally with the Supabase CLI. Some of the new features include: spreading related tables, related orders and anti-joins. + +- Learn more about [PostgREST 11](/blog/postgrest-11-prerelease) +- Visit the [CLI docs](/docs/guides/resources/supabase-cli) + +## Multilingual search in Postgres + +![Multilingual search in Postgres](/images/blog/lw6-community/pgroonga.jpg) + +One more thing + +We've released a new multilingual Full Text Search extension, PGroonga. It's fast, it's open source, and it's available on our platform today. If you've ever wanted to build a search engine for your app, then check out PGroonga. + +- Visit the [PGroonga website](https://pgroonga.github.io) +- Read the [Extensions Docs](/docs/guides/database/extensions) + +## Flutterflow for Flutter App Development + + + +
    + +Community Spotlight + +We partnered with the team at [Flutterflow](https://flutterflow.io/) to bring you a new way to build Flutter apps. Flutterflow is a low-code platform that allows you to build Flutter apps without writing any code. It's a great way to get started with Flutter and Supabase. + +- Watch the [tutorial](https://www.youtube.com/watch?v=hw9Q-NjASbU) +- Get Started with [Flutterflow](https://flutterflow.io/) + +## OneSignal for Push Notifications + + + +
    + +Community Spotlight + +We partnered with the team at [OneSignal](https://onesignal.com/) to offer push notifications in Supabase. OneSignal is a messaging platform allowing you to deliver push notifications, in-app messages, SMS, and emails to your users. + +- Watch the [tutorial](https://www.youtube.com/watch?v=mw0DLwItue4) +- Get Started with [OneSignal](https://onesignal.com/) + +## Getting Started + +Get started today with Supabase. It's free and open source. + +- [Like some memes on Twitter](https://twitter.com/supabase) +- [Star us on GitHub](https://github.com/supabase/supabase) +- [Join the Discord](https://discord.supabase.com) +- [Read the docs](https://supabase.com/docs) +- [Sign up](https://app.supabase.io/) diff --git a/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx b/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx new file mode 100644 index 00000000000..da45e32becf --- /dev/null +++ b/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx @@ -0,0 +1,70 @@ +--- +title: What's new in Postgres 15? +description: Describes the release of Postgres 15, new features and reasons to use it +author: pavel +image: lw6-community/pg15.png +thumb: lw6-community/pg15.png +tags: + - postgres + - launch-week +date: '2022-12-16' +toc_depth: 3 +--- + +The PostgreSQL community [released](https://www.postgresql.org/docs/current/release-15.html) version 15 (stable) in October 2022. Let's review some of the new features. + +## **The permission model is more secure** + +`CREATE` permission is revoked from all users except the database owner. It makes permission assigning more tunable ([details](https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PATTERNS)). And for the migrated database don't forget to revoke `CREATE` permission on the public schema manually to fit the new policy. + +There is a useful option `CREATE VIEW .. WITH security_invoker=on` to create a view that uses permissions of a view caller rather than a view creator to access underlying tables. With this, you should not worry that a user that doesn't have access to a table could see its data through a view. + +## **Performance speed-up** + +Sorting rows of data is a frequent operation inside the PostgreSQL code. It is used not only when you use the ORDER BY clause, but also in indices creation, table partitioning, etc. Furthermore, sorting is one of the most algorithmically expensive operations. So increasing speed up to 4 times of both in-memory and on-disk sorts in version 15 is one of the main reasons to upgrade. + +Window functions performance is also improved. + +## The **MERGE operation was introduced** + +A new `MERGE` operation is to modify target table data according to the provided source with many available conditional processing options. This allows data processing without writing procedural language functions or complex CTE queries. Essentially merge can work as conditional delete/insert/update and also this makes PostgreSQL syntax implementation closer to SQL:2008 standard. For details on MERGE uses see: [https://www.postgresql.org/docs/15/sql-merge.html](https://www.postgresql.org/docs/15/sql-merge.html) + +## **New features for logical replication** + +Logical replication is one of the fast-developing parts of PostgreSQL. Since version 15 two-phase commits are supported in logical replication. Also now you can choose parts of table data to logically replicate using i.e. some sets of rows and columns. In the case of replication conflict i.e. replicated data violate some constraint or there is a permission violation on a subscriber server user can choose to skip the conflicting transaction or disable the subscription until the user can decide how to handle the conflict. + +## **Increase parallelization** + +Parallel execution of queries using several worker processes is another part of PostgreSQL that develops fast. In version 15 `SELECT DISTINCT` queries that drop duplicate rows from output can improve performance by using parallel workers. + +## **JSON logging** + +Output log data as JSON structure helps logs processing and structured output on the client's side. + +## **Compressing options** + +In version 15 _Zstandard_ and _ZL4_ can be chosen instead of _pglz_ as a WAL compression method. WAL compression is useful to decrease disk space usage while safeguarding data integrity. + +When you make a database backup with the provided pg*basebackup extension you can also choose \_Zstandard* or _ZL4_ to compress database backups on the server side, to transfer less data over the network. + +## **New POSIX regexp functions** + +There are several new regular expressions functions that you may find useful for strings processing i.e. regexp_substr(), regexp_count(), etc. [Details](https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP) + +## **Full Changelog** + +You can find a full changelog and full list of new features in the [official changelog](https://www.postgresql.org/docs/15/release-15.html#id-1.11.6.6.5). + +## **Should you upgrade to PG15?** + +The main reason to switch to a new PostgreSQL version is the large number of bug fixes that each new version delivers. Bug fixes aren't as prominent as new features or performance improvements, but they often have a greater impact. While some bug fixes are applied to previous versions, these changes require modifications to the ABI, interface functions, and system catalog structures, often not possible in an already-released major version. + +So, the TL;DR: yes, you should update to improve stability. + +Upgrading is safe thanks to the half-year stabilization period between April's code freeze of every new feature and October's stable release. Generally, you'd rather find a bug in an old version than in a new one. + +Before choosing to upgrade, don't forget to check the list of rare cases that need [manual actions](https://www.postgresql.org/docs/current/release-15.html#id-1.11.6.6.4) before or after the upgrade. + +- If you're self-hosting, upgrading between major PostgreSQL is easily done with [pg_upgrade](https://www.postgresql.org/docs/current/pgupgrade.html) utility or a set of recommended practices in the [official docs](https://www.postgresql.org/docs/current/upgrading.html). +- If you're starting a new project on Supabase, you'll already be on PG15. +- If you want to upgrade an existing project, check out our [Upgrading](https://supabase.com/docs/guides/platform/migrating-and-upgrading-projects#upgrade-your-project) documentation. diff --git a/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx b/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx new file mode 100644 index 00000000000..30c6c59d777 --- /dev/null +++ b/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx @@ -0,0 +1,103 @@ +--- +title: pg_graphql v1.0 +description: Announcing the v1.0 release of pg_graphql +author: oli_rice +image: launch-week-6/pggraphql/og-pg-graphql.png +thumb: launch-week-6/pggraphql/og-pg-graphql.png +tags: + - graphql + - postgres + - launch-week +date: '2022-12-16' +toc_depth: 3 +--- + +Today we're announcing the 1.0 release of pg_graphql and its general availability on our platform. pg_graphql is a PostgreSQL extension that allows you to query your database using GraphQL. It is the foundation of GraphQL support in the Supabase stack. + +Since our first platform release, v0.2.1, the feature set of pg_graphql has steadily grown and stabilized. Despite being a pre-1.0, we've been extremely cautious with each new feature and have yet to introduce a backwards-incompatible change. With the 1.0 release we're formalizing that guarantee, subject to the SemVer spec. + +## Background + +pg_graphql was created to satisfy an extreme set of constraints. Mainly, [Supabase free tier](https://supabase.com/pricing) projects run on servers with 1 GB of memory. On those servers, we squeeze tuned versions of [PostgreSQL](https://github.com/supabase/postgres), [PostgREST](https://postgrest.org/en/stable/), and [GoTrue](https://github.com/supabase/gotrue). Every megabyte consumed by something that isn't PostgreSQL is another chance for an index to fall out of memory, or a large query to fail. + +Our philosophy when adding to the stack is to use existing open source tools wherever possible. We surveyed the available GraphQL → SQL options and found some excellent candidates in [Hasura](https://hasura.io/) and [Graphile](https://www.graphile.org/). Both support the set of features we're interested in, but consume significantly more memory than we could sacrifice on the free tier. Realizing that, we searched for an architecture that could meet our runtime constraints and performance requirements. + +## Architecture + +Our first prototype of pg_graphql PostgreSQL extension had a parser written in C (libgraphqlparser) with all business logic of transpiling GraphQL to SQL **written** in SQL. We exposed the extensions sole SQL function `graphql.resolve(...)` over HTTP using PostgREST's [RPC functionality](https://postgrest.org/en/stable/api.html#s-procs). With this approach, the memory footprint was too small to measure when accessed over HTTP. While memory-use sent us down this path, we discovered that leaning into Postgres primitives lead to some incredible synergies. To name a few: + +### Security + +Since data are accessed through a standard, unprivileged, SQL function, Postgres role permissions and Row Level Security (RLS) policies work exactly like they do in Postgres. Define your security model once, and it applies everywhere: SQL, REST, Realtime, and GraphQL + +### Always up-to-date + +No separate process means no roundtrip time. Inspecting the database's schema does not require any caching and is always in-sync. Knowing that the GraphQL and SQL schemas are aligned give us the confidence to compile GraphQL requests of any complexity into exactly one SQL query, [solving the N+1 query problem](https://medium.com/the-marcy-lab-school/what-is-the-n-1-problem-in-graphql-dd4921cb3c1a) and producing high throughput. + +### Scaling + +As an extension, pg_graphql's performance scales directly with the size of the database. When a user's performance needs grow, upgrading the database instance also scales up GraphQL throughput with no external processes to manage. + +### ACID - Atomicity, Consistency, Isolation, and Durability + +Databases have strong ACID guarantees. Being embedded in the database lets us claim those guarantees through the GraphQL API. For example, if any part of a multi-mutation GraphQL request fails, the entire request can roll back to leave the database in a consistent state. + +## From SQL to Rust + +Our pure [SQL implementation of the pg_graphql transpiler](https://github.com/supabase/pg_graphql/blob/bd0283718abaf329d98c69808f862594e9df5edc/pg_graphql--0.4.0.sql) carried us from v0.0.1 to v0.4.0. Ultimately, we started to feel some pain, although probably not in the way you'd expect. + +Opinions about business logic in SQL are notoriously split. In my view, there are some foot guns, but: + +- SQL has types +- SQL has functions +- Functions are composable + +Ergo, keep your functions pure and you've got a strongly typed functional programming paradigm. Taking that approach, the developer experience for pg_graphql was surprisingly excellent. The feedback cycle with [pg_regress](https://www.postgresql.org/docs/9.1/regress.html) is fast, and occasionally the type system even caught a bug or two. What more could you ask for? + +Somewhere around the 4,000 line count, things started to bog down. The rough shape of the codebase was coming into view, which made it clear where we could further extract common patterns into functions. At this point I learned two things: + +- SQL functions are “pass by value” (copy) so passing state around can get expensive +- The query planner tends to stop inlining functions when calls are deeply nested + +Combine those two facts with our GraphQL AST being a big ball of JSONB, and the GitHub issues about slow schema introspection on free tier started to trickle in. + +Enter [pgx](https://github.com/tcdi/pgx)… + +pgx is a rust framework for building Postgres extensions. It has a very polished onboarding experience and (as you would expect) full SQL interop. That made it straightforward to initially sprinkle some rust on pg_graphql's hotspots. When that went well, we ultimately rewrote pg_graphql from the ground up as a pure Rust project for the v0.5.0 release. + +One of rust's main selling points is zero cost abstractions. That means high-level concepts like generics incur no runtime penalty. Transitioning from SQL's expensive abstractions to rust's zero cost abstractions has been hugely satisfying as it enabled refactoring the codebase into a more maintainable state. Development velocity is up. Code quality is up. Performance is WAY up. + +As of 1.0, overhead introduced by pg_graphql is sub 300 *micro*seconds per request on free-tier hardware. When executed from SQL we see ~1060 queries per second per connection (no parallelism). If we include the entire Auth + HTTP stack, free tier can handle ~645 requests per second. On larger instance the stack handles upwards of 10k requests / second. + +```text +This is ApacheBench, Version 2.3 <$Revision: 1843412 $> +Server Software: postgrest/10.1.1 +Document Path: /graphql/v1 +Concurrency Level: 10 +Time taken for tests: 3.099 seconds +Complete requests: 2000 +Requests per second: 645.40 [#/sec] (mean) +Time per request: 15.494 [ms] (mean) +Time per request: 1.549 [ms] (mean, across all concurrent requests) +``` + +## Roadmap + +While v1.0 is an important milestone for stability, there's plenty of room to expand the feature set. For example, some commonly requested features on the immediate roadmap are: + +- Extended filtering options + - `startsWith` for the `String` type + - nestable `and`/ `or` blocks +- Support for user-defined functions +- Support for views + +Longer term we look forward to experimenting with more ambitions features like an API for migrations, integrations with 3rd-party services through [supabase/wrappers](https://github.com/supabase/wrappers), and a scalable solution for subscriptions. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx b/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx new file mode 100644 index 00000000000..243adfdb0e1 --- /dev/null +++ b/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx @@ -0,0 +1,50 @@ +--- +title: 'Point in Time Recovery is now available for Pro projects' +description: "We're making PITR available for more projects, with a new Dashboard UI that makes it simple to use." +author: angelico_de_los_reyes +image: launch-week-6/pitr/og-pitr.png +thumb: launch-week-6/pitr/og-pitr.png +tags: + - launch-week + - postgres + - backups +date: '2022-12-16' +toc_depth: 3 +--- + +When we announced Point-in-Time a few months ago, it was only available for Enterprise customers. Today, we're making PITR available for more projects, with a new Dashboard UI that makes it simple to use. + +Pro-tier projects created from August 2022 onwards (excluding Northeast Asia / Seoul region), can now enable Point In Time Recovery (PITR) from the dashboard. Projects must have the "Small" compute add-on to ensure that PITR operates smoothly behind the scenes. + +For older projects, don't worry - we're working on making it available for everybody. In the meantime, if you would like to have PITR enabled for your ineligible project, reach out directly [here](https://app.supabase.com/support/new), or stay tuned for further updates. + +## What is Point in Time Recovery? + +![point in time recovery overview](/images/blog/launch-week-6/pitr/pitr-overview.png) + +Point in Time Recovery provides the ability for a database to be restored at any specified point in time. This is useful when averting disasters, for all those times that a, _cough_, natural calamity strikes (like accidentally dropping a table). With PITR, the database can be restored to a state it was in mere seconds before trouble. + +All of this is made possible by a combination of physical backups and archives from the [Write Ahead Log (WAL)](https://www.postgresql.org/docs/current/wal-intro.html). Physical backups provide a snapshot of the underlying directory of the database, while WAL files contain records of every change made in the database. + +Under the hood, we use [WAL-G](https://github.com/wal-g/wal-g), an open source archival and restoration tool, to handle all aspects of PITR. On a daily basis, WAL-G takes a snapshot of the database and sends it to our storage servers. Throughout the day, as database transactions occur, WAL files are generated and uploaded to archived. + +## Should I enable PITR? + +![point in time recovery date selection](/images/blog/launch-week-6/pitr/pitr-date-selection.png) + +Consider your Recovery Point Objective (RPO) when deciding whether to enable Point in Time Recovery. RPO is the threshold for how much data, measured in time, a business could lose when disaster strikes. This is dependent on a business and its underlying requirements. The agreed upon RPO would be a deciding factor in choosing which solution best fits a project. + +While all Pro-tier projects and above are backed up on a daily basis, this means that at the worst case, a project could lose up to 24 hours worth of data if disaster hits at the most inopportune time. With Point in Time Recovery however, backups are made at much shorter intervals, shortening the RPO. WAL files are backed up at two minute intervals. This could be faster if it hits a certain file threshold before the the two minute mark. + +## Getting started + +Enabling Point in Time Recovery could be done [in the Dashboard](https://app.supabase.com/project/_/settings/billing/update/pro). Retention for backups used by PITR is set to up to 7 days by default but could be increased to up to 28 days via self-serve. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx b/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx new file mode 100644 index 00000000000..bbef228a26d --- /dev/null +++ b/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx @@ -0,0 +1,226 @@ +--- +title: PostgREST 11 pre-release +description: Describes new features of PostgREST 11 pre-release +author: steve_chavez +image: lw6-community/postgrest.png +thumb: lw6-community/postgrest.png +tags: + - postgres + - launch-week +date: '2022-12-16' +toc_depth: 3 +--- + +PostgREST 11 is not wrapped up yet, however a pre-release with the **[latest features and fixes](https://github.com/PostgREST/postgrest/releases/tag/v10.1.1.20221212)** +is available on the Supabase CLI. + +In this blog post we'll cover some of the improved querying capabilities: spreading related tables, related orders and anti-joins. + +## Spreading related tables + +Very often the way we structure a database is not the way we want to present it to the frontend application. For example, let's assume we have a `films` and `technical_specs` tables and +they form a one-to-one relationship. + +Using PostgREST resource embedding, we can query them in one request like so + +From HTTP: + +```http +GET /films?select=title,technical_specs(camera,laboratory,sound_mix) +``` + +or JavaScript: + +```jsx +const { data, error } = await supabase.from('films').select(` + title, + technical_specs ( + camera, laboratory, duration + ) + `) +``` + +Response: + +```json +[ + { + "title": "Pulp Fiction", + "technical_specs": { + "camera": "Arriflex 35-III", + "laboratory": "DeLuxe, Hollywood (CA), USA (color)", + "duration": "02:34:00" + } + }, + "..." +] +``` + +But we'd like to present a “flattened” result to the frontend, without the `technical_specs` object. For this we could create a new database view or function that shapes the json the way we want, but creating extra database objects is not always convenient. + +Using the new “spread” operator(syntax borrowed from [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)), we can expand a related table columns and remove the nested object. + +From HTTP: + +```jsx +GET /films?select=title,...technical_specs(camera,laboratory,duration) +``` + +or JavaScript: + +```jsx +const { data, error } = await supabase.from('films').select(` + title, + ...technical_specs ( + camera, laboratory, duration + ) + `) +``` + +Response: + +```json +[ + { + "title": "Pulp Fiction", + "camera": "Arriflex 35-III", + "laboratory": "DeLuxe, Hollywood (CA), USA (color)", + "duration": "02:34:00" + }, + "..." +] +``` + +This only works for one-to-one and many-to-one relationships for now but we're looking at ways to remove this restriction. + +## Order by related tables + +It's also a common use case to order a table by a related table column. For example, suppose you'd like to order `films` based on the `technical_specs.duration` column. + +You can now do it like so: + +From HTTP: + +```http +GET /films?select=title,...technical_specs(duration)&order=technical_specs(duration).desc +``` + +or JavaScript: + +```jsx +const { data, error } = await supabase + .from('films') + .select(` + title, + ...technical_specs ( + duration + ) + `) + .order('technical_specs(duration)', { descending: true })) +``` + +Response: + +```json +[ + { + "title": "Amra Ekta Cinema Banabo", + "duration": "21:05:00" + }, + { + "title": "Resan", + "duration": "14:33:00" + }, + "..." +] +``` + +Similarly to spreading related tables, this only works for one-to-one and many-to-one relationships. + +## Anti-Joins + +To do the equivalent of a left anti-join, you can now filter the rows where the related table is `null`. + +From HTTP: + +```http +GET /films?select=title,nominations()&nominations=is.null +``` + +or JavaScript: + +```jsx +const { data, error } = await supabase + .from('films') + .select(` + title, + nominations() + `) + .is('nominations', null)) +``` + +Response: + +```json +[ + { + "title": "Memories of Murder" + }, + { + "title": "Rush" + }, + { + "title": "Groundhog Day" + }, + "..." +] +``` + +Note that `nominations` doesn't select any columns so they don't show on the resulting response. + +The equivalent of an inner join can be done by filtering the rows where the related table is `not null`. + +```http +GET /films?select=title,nominations(rank,...competitions(name))&nominations=not.is.null +``` + +```jsx +const { data, error } = await supabase + .from('films') + .select( + ` + title, + nominations(rank,...competitions(name)) + ` + ) + .not('nominations', 'is', null) +``` + +Response: + +```json +[ + { + "title": "Pulp Fiction" + "nominations": [ + {"rank": 1, "name": "Palme d'Or"}, + {"rank": 1, "name": "BAFTA Film Award"}, + {"..."} + ] + }, + "..." +] +``` + +This was already possible with the `!inner` modifier([introduced on PostgREST 9](https://supabase.com/blog/postgrest-9#resource-embedding-with-inner-joins)) +but the `not null` filter is more flexible and can be used with an [or filter](https://supabase.com/docs/reference/javascript/or) to combine related tables' conditions. + +## Try it out + +This pre-release is not deployed to Supabase cloud but you can try it out locally with the [Supabase CLI](https://supabase.com/docs/reference/cli/introduction). + +```bash +$ supabase start +``` + +Please try it and report any bugs, suggestions or ideas! diff --git a/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx new file mode 100644 index 00000000000..3d1418be10d --- /dev/null +++ b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx @@ -0,0 +1,96 @@ +--- +title: 'Supabase Vault is now in Beta' +description: 'A Postgres extension to store encrypted secrets and encrypt data.' +author: michel +image: launch-week-6/vault/og-vault.png +thumb: launch-week-6/vault/og-vault.png +tags: + - launch-week + - postgres + - encryption +date: '2022-12-16' +toc_depth: 3 +--- + +During our last Launch Week we [announced](/blog/supabase-vault) Supabase Vault as our “one more thing”. Today we're releasing it progressively across the platform. + +Vault is a new Postgres extension and accompanying Supabase UI that makes it safe and easy to store encrypted secrets and encrypt other stored data in your database. This foundation opens up a lot of possibilities for Postgres that go beyond what is available in a stock distribution. From a product perspective we're grouping various features under the “Vault banner”. Let's explore a few of these features. + +## Secrets Management + +Practically speaking, the Vault is a table of Secrets and Encryption Keys that are stored using [Authenticated Encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) on disk, but available in decrypted form through a Postgres view so that the secrets can be used by applications from SQL. Because the secrets are stored encrypted and authenticated, any backups or replication streams also preserve this encryption in a way that can't be forged. + +We've created a dashboard UI for the Vault that makes storing secrets easy. Click a button and type in your secret, optionally create a new key that is referenced by id (or use the existing default), and submit. Your secret is now stored on disk encrypted using the specified key id. + + + +There are two main parts to the Vault UI, Secrets and Encryption Keys: + +- **Secrets:** Use the Vault to store Secrets - everything from Environment Variables to API Keys. You can use these Secrets anywhere in your database: Postgres [Functions](/docs/guides/database/functions), Triggers, and [Webhooks](/docs/guides/database/webhooks). From a SQL perspective, accessing secrets is as easy as querying a table (or in this case, a view). The underlying secrets tables will be stored in encrypted form. +- **Encryption Keys:** encryption keys are used to encrypt data inside your database. Fun fact: the Secrets you store in the Vault are encrypted with an Encryption Key which we set up by default and is not accessible to SQL or stored in your database alongside the same data it is used to encrypt. You can create different Encryption Keys for different purposes, for example: one for encrypting user-data, and another for application-data. + +## Transparent Column Encryption (TCE) + +Our recent [blog post](/blog/transparent-column-encryption-with-postgres) describes TCE in-depth. TCE is one of the safest ways to encrypt your data so that it doesn't leak into logs and backups, as well as providing your users with row-level authenticated encryption. TCE is the foundational feature of the Vault, but you can use it on your own tables if you choose to if the Vault isn't sufficient for your needs, for example if you have multiple tables that you wish to have encrypted columns. Any Postgres value that can be cast to `text` or `bytea` can use TCE to encrypt the data that is stored to disk. + +### Encrypting columns + +In the “New Column” flow on the Dashboard, you can select that a `text` or `bytea` column is encrypted, and select an existing key id or create a new one. This is functionally identical to the Vault above, but you can apply it to any of your existing tables. In a sense the Vault is a pre-created table and UI for you to get started quickly storing secrets, and to be a centralized point for “global” secrets management, but your not stuck with just that, you can encrypt multiple columns in multiple tables, how you want to store your secret data can be entirely up to you. + +![Encrypting columns](/images/blog/launch-week-6/vault/vault-encrypting-columns.png) + +Once you've setup an encrypted column, just insert data into the table like you would any other table. If you put in an email address for example, you will see that what is stored is not an email at all, but an encrypted value. + +![Encrypted data](/images/blog/launch-week-6/vault/vault-encrypted-data.png) + +Decrypted data can be accessed by a special view that is automatically created whenever you create an encrypted column on a table. This view decrypts the data row-by-row as you access it. By default this view is called `decrypted_`, so in the example provided, the decryption view for the `profiles` table is `decrypted_profiles`. In addition to the existing `emails` column, there is a new column in the view called `decrypted_emails` that contains the decrypted email value. It's that simple! + +![Decrypted data](/images/blog/launch-week-6/vault/vault-decrypted-data.png) + +## Deep Dive on How The Vault works + + + +As we mentioned, the Vault uses pgsodium's Transparent Column Encryption (TCE) to store secrets in an authenticated encrypted form. There are some details around that you may be curious about, what does authenticated mean, and where are encryption keys store? This section explains those details. + +The first important feature of TCE is that it uses an [Authenticated Encryption with Associated Data]() encryption algorithm based on libsodium. “Authenticated Encryption” means that in addition to the data being encrypted, it is also “signed” so that it cannot be forged, the decryption function verifies that the signature is valid **before decrypting the value**. “Associated Data” means that in addition to signing the secret, you can include any other columns in your row in the signature computation, “associating” those columns with the secret. This doesn't encrypt those other columns, but it does ensure that **they are authentic** and cannot be forged because they are included in the secret's signature. So you know when you restore your database dumps, not only are the secrets safe, but also the “associated” columns are also authentic and unforged. + +Another important feature of pgsodium is that the encryption keys are never stored in the database alongside the encrypted data, instead, only a **Key ID** is stored, which refers to a key that is only accessible outside of SQL. Even if an attacker can capture a dump of your entire database, they will see only encrypted data and key ids, **never the raw key itself**. This is an important safety precaution, there would be no point in storing the encryption key in the database alongside the encrypted data, this would be like locking your front door but leaving the key in the lock! Storing the key outside the database fixes this issue. + +You might be wondering, ok then where are the keys stored? Supabase creates and manages the root keys from which all key ids are derived in our internal customer backend systems. We keep this key safe and separate from your data, and provide an alternate dashboard endpoint for accessing the key if you want to decrypt your data outside of Supabase. + +## Future possibilities + +Privacy is becoming one of the most important features in a modern product. Supabase's embrace of the pgsodium extension aims to make this simple. Some of the possibilities we are looking into are: + +- **End-to-end encryption**: give your users the ability to encrypt their personal data so even you, the developer cannot access it, using the libsodium [encrypted streams](https://doc.libsodium.org/secret-key_cryptography/secretstream) API that is exposed by pgsodium. After exchanging keys, parties can stream unlimited amounts of data from peer to peer without being intercepted by any party in between, including Supabase. +- **Group encryption**: have you ever joined a group on Whatsapp and been frustrated that you can't read the previous messages? That's because group encryption is hard. We hope to make that easier using new algorithms like [signcryption](https://github.com/jedisct1/libsodium-signcryption) to support multi-party encrypted messages that can be easily encoded into a token format and use to support streaming encryption keys. +- **Public Key Management:** Public Key Encryption can be hard, but pgsodium makes it easier by exposing all of the public key encryption functions that are supported by libsodium. Making and distributing key pairs is now easy, no need to run arcane GPG scripts or mess with SSL libraries. libsodium contains state of the art public key encryption, and by extension so does pgsodium. These features are available now on the Supabase platform and offer a lot of possibilities to unshackle developers from other confusing and inadequate solutions available today. + +### Using the Vault + +You'll see the Vault appear in the Dashboard over the next month. If you want to use Vault today, email growth@supabase.com and we'll enable it on your account. Vault is available for all customers (including the Free-tier). + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) +- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) diff --git a/apps/www/components/EnterpriseContactForm.tsx b/apps/www/components/EnterpriseContactForm.tsx deleted file mode 100644 index f0eda1f785d..00000000000 --- a/apps/www/components/EnterpriseContactForm.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import { Button, Form, Input, Listbox } from 'ui' -import { useState } from 'react' -import countries from '~/data/Countries.json' -import supabase from '~/lib/supabase' - -const INITIAL_VALUES = { - companyName: '', - contactFirstName: '', - contactLastName: '', - contactEmail: '', - contactPhone: '', - companySize: '', - details: '', - country: 'US', -} - -const validate = (values: any) => { - const errors: any = {} - - if (!values.companyName) { - errors.companyName = 'Required' - } - - if (!values.contactFirstName) { - errors.contactFirstName = 'Required' - } - - if (!values.contactLastName) { - errors.contactLastName = 'Required' - } - - if (!values.contactEmail) { - errors.contactEmail = 'Required' - } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.contactEmail)) { - errors.contactEmail = 'Invalid email address' - } - - return errors -} - -const EnterpriseContactForm = () => { - const [formSubmitted, setFormSubmitted] = useState(false) - - const handleFormSubmit = async (values: typeof INITIAL_VALUES, { resetForm }: any) => { - const { error } = await supabase.from('enterprise_contacts').insert([ - { - company_name: values.companyName, - contact_name: `${values.contactFirstName} ${values.contactLastName}`, - contact_first_name: values.contactFirstName, - contact_last_name: values.contactLastName, - contact_email: values.contactEmail, - contact_phone: values.contactPhone, - company_size: values.companySize, - details: values.details, - country: values.country, - }, - ]) - - // TODO: handle error - console.log('error:', error) - if (!error) { - resetForm() - - setFormSubmitted(true) - } - } - - return ( -
    -
    - {({ values, isSubmitting }: any) => { - const selectedCountry = countries.find((country) => country.code === values['country']) - const phonePlaceholder = - selectedCountry !== undefined ? `+${selectedCountry.phone_code}` : '' - - return ( -
    -
    - -
    - -
    -
    - -
    - -
    - -
    -
    - -
    - -
    - -
    - - - {'---'} - - - 1-10 Employees - - - 11-50 Employees - - - 51-200 Employees - - - 201-500 Employees - - - 501-1000 Employees - - - 1001-5000 Employees - - - 5001+ Employees - - -
    - -
    - -
    - -
    - - {countries.map(({ code, name }) => ( - - {name} - - ))} - -
    - -
    - -
    - -
    - -
    -
    - ) - }} -
    - - {formSubmitted && ( -

    Thanks, we'll reach out to you shortly.

    - )} -
    - ) -} - -export default EnterpriseContactForm diff --git a/apps/www/components/LaunchWeek/lw6_days.json b/apps/www/components/LaunchWeek/lw6_days.json index 661f5a66576..e961beefa62 100644 --- a/apps/www/components/LaunchWeek/lw6_days.json +++ b/apps/www/components/LaunchWeek/lw6_days.json @@ -67,27 +67,48 @@ ] }, { - "title": "Day 4", - "shipped": false, + "title": "Supabase Wrappers - FDW Framework", + "shipped": true, "date": "15 Dec 2022", - "description": "Day 4", + "description": "Supabase Wrappers", "d": 4, "dd": "Thursday", - "youtube_id": "CGZr5tybW18", - "blogpost": "https://supabase.com/blog", + "youtube_id": "QA2qC5F-4OU", + "blogpost": "/blog/postgres-foreign-data-wrappers-rust", "docs": "https://supabase.com/docs", - "steps": [] + "steps": [ + { + "title": "Supabase Wrappers", + "blog": "/blog/postgres-foreign-data-wrappers-rust", + "docs": "https://supabase.github.io/wrappers/", + "isNew": true, + "description": "Connect Postgres to external systems with Postgres Foreign Data Wrappers" + } + ] }, { - "title": "Day 5", - "shipped": false, + "title": "Supabase Vault Release", + "shipped": true, "date": "16 Dec 2022", - "description": "Day 5", + "description": "Vault Release", "d": 5, "dd": "Friday", - "youtube_id": "CGZr5tybW18", + "youtube_id": "6bGQotxisoY", "blogpost": "https://supabase.com/blog", "docs": "https://supabase.com/docs", - "steps": [] + "steps": [ + { + "title": "Vault Release", + "blog": "/blog/vault-now-in-beta", + "isNew": true, + "description": "" + }, + { + "title": "Transparent Column Encryption", + "description": "Faster asset delivery, now even faster.", + "blog": "/blog/transparent-column-encryption-with-postgres", + "isNew": true + } + ] } ] diff --git a/apps/www/components/Partners/BecomeAPartners.tsx b/apps/www/components/Partners/BecomeAPartners.tsx index 0e5a53c171b..b599612c4a6 100644 --- a/apps/www/components/Partners/BecomeAPartners.tsx +++ b/apps/www/components/Partners/BecomeAPartners.tsx @@ -1,206 +1,19 @@ -import { Button, Form, Input, InputNumber, Select } from 'ui' -import { useState } from 'react' -import countries from '~/data/Countries.json' +import { Button } from 'ui' import { SupabaseClient } from '~/lib/supabase' - -const INITIAL_VALUES = { - type: 'expert', - first: '', - last: '', - company: '', - size: '', - title: '', - email: '', - phone: '', - country: 'US', - details: '', -} - -const validate = (values: any) => { - const errors: any = {} - - if (!values.first) { - errors.first = 'Required' - } - - if (!values.last) { - errors.last = 'Required' - } - - if (!values.email) { - errors.email = 'Required' - } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { - errors.email = 'Invalid email address' - } - - return errors -} +import Link from 'next/link' export default function BecomeAPartner({ supabase }: { supabase: SupabaseClient }) { - const [formSubmitted, setFormSubmitted] = useState(false) - - const handleFormSubmit = async (values: any) => { - const { error } = await supabase.from('partner_contacts').insert([ - { - type: values.type, - first: values.first, - last: values.last, - company: values.company, - size: Number(values.size), - title: values.title, - email: values.email, - website: values.email.split('@')[1], - phone: values.phone, - country: values.country, - details: values.details, - }, - ]) - - // TODO: handle error - console.log('error:', error) - - setFormSubmitted(true) - } - return (
    -
    -

    Become a Partner

    - -
    - {({ isSubmitting }: any) => ( -
    -
    - -
    - -
    -
    - -
    - -
    - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    -
    - )} -
    - - {formSubmitted &&

    Thanks, we'll reach out to you shortly 👁⚡️👁

    } +
    +

    Ready to work together?

    + + + + +
    ) diff --git a/apps/www/components/Sections/GithubExamples.tsx b/apps/www/components/Sections/GithubExamples.tsx index 788088361dc..16b1c23d20c 100644 --- a/apps/www/components/Sections/GithubExamples.tsx +++ b/apps/www/components/Sections/GithubExamples.tsx @@ -31,19 +31,15 @@ function GithubExamples() { Supported by a network of early advocates, contributors, and champions.

    - + - - -
    - - + +
    + Jump to current day +
    +
    {process.env.NEXT_PUBLIC_LW_STARTED && ( <> - +
    -
    - + + >
    Who we hire at Supabase @@ -248,7 +255,34 @@ export default function launchweek() {
    Read blogpost
    - + +
    +
    + +
    +
    + + +
    +
    +
    + +
    +
    + Wrap Up + Everything we shipped +
    +
    +
    + +
    + Read blogpost +
    +
    @@ -264,7 +298,13 @@ export default function launchweek() { justified={false} bordered={false} chevronAlign="right" - defaultValue={[day1.d.toString(), day2.d.toString(), day3.d.toString()]} + defaultValue={[ + day1.d.toString(), + day2.d.toString(), + day3.d.toString(), + day4.d?.toString(), + day5.d?.toString(), + ]} >
    {day1.description} @@ -389,7 +429,7 @@ export default function launchweek() { {day3.steps.length > 0 && (
    {day4.steps.length > 0 && ( -
    +
    -
    +
    + +
    +
    + +
    +
    {day4.steps[0].title} - + New
    - -
    -
    - {/* inset 0px 130px 50px -52px #121f1e; */} -
    - - New - - {day4.steps[1].title} -
    - +
    )}
    -
    +
    {day5.steps.length > 0 && ( -
    -
    -
    - {day5.steps[0].title} - - New - + <> +
    +
    +
    + +
    +
    + +
    +
    + + {day5.steps[0].title} + + + New + +
    +
    - -
    -
    -
    - - New - - {day5.steps[1].title} +
    +
    + +
    +
    + +
    +
    + + New + + + {day5.steps[1].title} + +
    +
    -
    -
    +

    Community

    + +

    + One more thing +

    +
    +
    +
    + +
    +
    + +
    +
    + + Updated + + + pg_graphql v1.0 + +
    + +
    +
    +
    + +
    +
    + +
    +
    + + New + + + Custom Domains + +
    + +
    +
    +
    + +
    +
    + +
    +
    + + New + + + Point-in-time recovery + +
    + +
    +
    +
    + +
    +
    + +
    +
    + + Experimental + + + pg_crdt + +
    + +
    +
    +
    + +
    +
    + +
    +
    + + Upgrade + + + Postgres 15 + +
    + +
    +
    +
    + +
    +
    + +
    +
    + + Upgrade + + + PostgREST 11 + +
    + +
    +
    + )}
    @@ -518,6 +1029,9 @@ export default function launchweek() { )} + + +
    diff --git a/apps/www/pages/launch-week/launchWeek.module.css b/apps/www/pages/launch-week/launchWeek.module.css index c37b14deb0e..2eec5b33b3b 100644 --- a/apps/www/pages/launch-week/launchWeek.module.css +++ b/apps/www/pages/launch-week/launchWeek.module.css @@ -9,3 +9,17 @@ .community { background-image: radial-gradient(closest-side at 50% 50%, #d9eeef, #dbeef0, white); } + +.wrappers > span { + left: -200px !important; +} + +.community_wrappers > span { + left: -400px !important; +} + +@media (max-width: 768px) { + .community_wrappers > span > img { + object-fit: contain !important; + } +} diff --git a/apps/www/pages/legal/soc2.tsx b/apps/www/pages/legal/soc2.tsx deleted file mode 100644 index f5fc2a80fac..00000000000 --- a/apps/www/pages/legal/soc2.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import Link from 'next/link' -import CTABanner from 'components/CTABanner/index' -import Layout from '~/components/Layouts/Default' -import SectionContainer from '~/components/Layouts/SectionContainer' -import SOC2RequestForm from '~/components/SOC2RequestForm' - -const SOC2 = () => { - return ( - - -
    -
    -
    -

    SOC2

    -

    - As a database company, being SOC2 compliant is important when handling sensitive - customer data. Supabase is currently SOC2 Type 1 compliant and we're also working on - getting certified for SOC2 Type 2 and HIPAA next. -

    - -

    You can request for our latest SOC 2 document by submitting your request here.

    - - -
    -
    -
    -
    - -
    - ) -} -export default SOC2 diff --git a/apps/www/pages/pricing/index.tsx b/apps/www/pages/pricing/index.tsx index a51809c5dec..75e03711b85 100644 --- a/apps/www/pages/pricing/index.tsx +++ b/apps/www/pages/pricing/index.tsx @@ -76,7 +76,7 @@ export default function IndexPage() { }, { name: 'Enterprise', - href: '/contact/enterprise', + href: 'https://forms.supabase.com/enterprise', description: 'For large-scale applications managing serious workloads.', features: [ `Point in time recovery`, @@ -575,7 +575,7 @@ export default function IndexPage() { Designated support team, account manager and technical specialist

    - +
    )} - {!isOwner && ( -
    - -
    - )} +
    + + + + + {!canLeave && ( + + +
    + + An organization requires at least 1 owner + +
    +
    + )} +
    +
    diff --git a/studio/components/interfaces/Organization/TeamSettings/TeamSettings.utils.ts b/studio/components/interfaces/Organization/TeamSettings/TeamSettings.utils.ts index 37ea52a0822..9651dacc86c 100644 --- a/studio/components/interfaces/Organization/TeamSettings/TeamSettings.utils.ts +++ b/studio/components/interfaces/Organization/TeamSettings/TeamSettings.utils.ts @@ -1,4 +1,4 @@ -import { Role } from 'types' +import { Member, Role } from 'types' import { checkPermissions } from 'hooks' import { PermissionAction } from '@supabase/shared-types/out/constants' @@ -23,3 +23,12 @@ export const getRolesManagementPermissions = ( return { rolesAddable, rolesRemovable } } + +export const hasMultipleOwners = (members: Member[] = [], roles: Role[] = []) => { + const membersWhoAreOwners = members.filter((member) => { + const [memberRoleId] = member.role_ids ?? [] + const role = roles.find((role: Role) => role.id === memberRoleId) + return role?.name === 'Owner' && !member.invited_at + }) + return membersWhoAreOwners.length > 1 +} diff --git a/studio/stores/authConfig/schema/AuthProviders/AuthProvidersFormValidation.tsx b/studio/stores/authConfig/schema/AuthProviders/AuthProvidersFormValidation.tsx index b51f6d754f1..d1a2a1cccbf 100644 --- a/studio/stores/authConfig/schema/AuthProviders/AuthProvidersFormValidation.tsx +++ b/studio/stores/authConfig/schema/AuthProviders/AuthProvidersFormValidation.tsx @@ -48,7 +48,7 @@ const PROVIDER_EMAIL = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -279,7 +279,7 @@ const PROVIDER_PHONE = { misc: { iconKey: 'phone-icon4', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -310,7 +310,7 @@ Client identifier when authenticating or validating users. title: 'Secret key', description: ` The secret key is a JWT token that must be generated. -[Learn more](https://supabase.com/docs/guides/auth/auth-apple#generate-a-client_secret)`, +[Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#generate-a-client_secret)`, type: 'string', isSecret: true, }, @@ -332,7 +332,7 @@ The secret key is a JWT token that must be generated. iconKey: 'apple-icon', requiresRedirect: true, helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, alert: { title: `Apple secrets will self expire every 6 months`, description: `You will need to regenerate before the 6 months elapses otherwise your users using Apple Login will no longer be able to log back in.`, @@ -357,7 +357,7 @@ const EXTERNAL_PROVIDER_AZURE = { EXTERNAL_AZURE_SECRET: { // [TODO] Change docs title: 'Secret Value', - description: `Enter the data from Value, not the Secret ID. [Learn more](https://supabase.com/docs/guides/auth/auth-azure#obtain-a-secret-id)`, + description: `Enter the data from Value, not the Secret ID. [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-azure#obtain-a-secret-id)`, type: 'string', isSecret: true, }, diff --git a/studio/stores/authConfig/schema/AuthProviders/AuthTemplatesValidation.tsx b/studio/stores/authConfig/schema/AuthProviders/AuthTemplatesValidation.tsx index 82320e55bd9..526e91022a9 100644 --- a/studio/stores/authConfig/schema/AuthProviders/AuthTemplatesValidation.tsx +++ b/studio/stores/authConfig/schema/AuthProviders/AuthTemplatesValidation.tsx @@ -30,7 +30,7 @@ export const CONFIRMATION: FormSchema = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -61,7 +61,7 @@ export const INVITE: FormSchema = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -92,7 +92,7 @@ export const MAGIC_LINK: FormSchema = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -123,7 +123,7 @@ export const EMAIL_CHANGE: FormSchema = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, } @@ -154,7 +154,7 @@ export const RECOVERY: FormSchema = { misc: { iconKey: 'email-icon2', helper: `To complete setup, add this authorisation callback URL to your app's configuration in the Apple Developer Console. - [Learn more](https://supabase.com/docs/guides/auth/auth-apple#configure-your-services-id)`, + [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#configure-your-services-id)`, }, }