Merge master resolve conflicts

This commit is contained in:
Joshen Lim committed 2025-09-08 15:09:00 +08:00
commit e78a3ef3c1
261 files changed
+11129 -2682

No files matched your search

+1
View File
@@ -46,6 +46,7 @@ jobs:
apps/docs
apps/www/.env.local.example
examples
packages
supabase
- uses: pnpm/action-setup@v4
+10
View File
@@ -20,6 +20,16 @@ You can start editing the page by modifying `app/page.tsx`. The page auto-update
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
### Watching for MDX changes
If you would like to watch for changes to MDX files with hot reload, you can run the following command in a separate Terminal shell:
```
pnpm content:dev
```
This runs Contentlayer concurrently and watches for any changes.
## Learn More
To learn more about Next.js, take a look at the following resources:
+1
View File
@@ -10,6 +10,7 @@
"build:registry": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --log-level silent --write \"registry/**/*.{ts,tsx,mdx}\" --cache",
"start": "next start",
"lint": "next lint",
"content:dev": "contentlayer2 dev",
"content:build": "contentlayer2 build",
"clean": "rimraf node_modules .next .turbo",
"typecheck": "contentlayer2 build && tsc --noEmit -p tsconfig.json"
+30 -12
View File
@@ -3,6 +3,7 @@ import Link from 'next/link'
import { cn, IconBackground, TextLink } from 'ui'
import { IconPanel } from 'ui-patterns/IconPanel'
import { isFeatureEnabled } from 'common'
import MenuIconPicker from '~/components/Navigation/NavigationMenu/MenuIconPicker'
import { MIGRATION_PAGES } from '~/components/Navigation/NavigationMenu/NavigationMenu.constants'
import { GlassPanelWithIconPicker } from '~/features/ui/GlassPanelWithIconPicker'
@@ -10,6 +11,14 @@ import { IconPanelWithIconPicker } from '~/features/ui/IconPanelWithIconPicker'
import HomeLayout from '~/layouts/HomeLayout'
import { BASE_PATH } from '~/lib/constants'
const { sdkCsharp, sdkDart, sdkKotlin, sdkPython, sdkSwift } = isFeatureEnabled([
'sdk:csharp',
'sdk:dart',
'sdk:kotlin',
'sdk:python',
'sdk:swift',
])
const generateMetadata = async (_, parent: ResolvingMetadata): Promise<Metadata> => {
const parentAlternates = (await parent).alternates
@@ -119,31 +128,37 @@ const clientLibraries = [
title: 'Javascript',
icon: 'reference-javascript',
href: '/reference/javascript/introduction',
enabled: true,
},
{
title: 'Flutter',
icon: 'reference-dart',
href: '/reference/dart/introduction',
enabled: sdkDart,
},
{
title: 'Python',
icon: 'reference-python',
href: '/reference/python/introduction',
enabled: sdkPython,
},
{
title: 'C#',
icon: 'reference-csharp',
href: '/reference/csharp/introduction',
enabled: sdkCsharp,
},
{
title: 'Swift',
icon: 'reference-swift',
href: '/reference/swift/introduction',
enabled: sdkSwift,
},
{
title: 'Kotlin',
icon: 'reference-kotlin',
href: '/reference/kotlin/introduction',
enabled: sdkKotlin,
},
]
@@ -224,18 +239,21 @@ const HomePage = () => (
</div>
<div className="grid col-span-8 grid-cols-12 gap-6 not-prose">
{clientLibraries.map((library) => {
return (
<Link
href={library.href}
key={library.title}
passHref
className="col-span-6 md:col-span-4"
>
<IconPanelWithIconPicker {...library} />
</Link>
)
})}
{clientLibraries
.filter((library) => library.enabled)
.map((library) => {
return (
<Link
href={library.href}
key={library.title}
passHref
className="col-span-6 md:col-span-4"
>
<IconPanelWithIconPicker {...library} />
</Link>
)
})}
</div>
</div>
@@ -1,6 +1,7 @@
'use client'
import { usePathname } from 'next/navigation'
import { isFeatureEnabled } from 'common'
import { cn } from 'ui'
import { ExpandableVideo } from 'ui-patterns/ExpandableVideo'
import { Toc, TOCItems, TOCScrollArea } from 'ui-patterns/Toc'
@@ -18,6 +19,8 @@ const GuidesTableOfContents = ({ className, video }: { className?: string; video
const pathname = usePathname()
const { toc } = useTocAnchors()
const showFeedback = isFeatureEnabled('feedback:docs')
const tocVideoPreview = `https://img.youtube.com/vi/${video}/0.jpg`
return (
@@ -28,9 +31,11 @@ const GuidesTableOfContents = ({ className, video }: { className?: string; video
<ExpandableVideo imgUrl={tocVideoPreview} videoId={video} />
</div>
)}
<div className="pl-5">
<Feedback key={pathname} />
</div>
{showFeedback && (
<div className="pl-5">
<Feedback key={pathname} />
</div>
)}
{toc.length !== 0 && (
<Toc className="-ml-[calc(0.25rem+6px)]">
<h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
+20 -11
View File
@@ -3,12 +3,17 @@
import { ChevronRight, Play, Sparkles } from 'lucide-react'
import Link from 'next/link'
import { useBreakpoint } from 'common'
import { isFeatureEnabled, useBreakpoint } from 'common'
import { cn, IconBackground } from 'ui'
import { IconPanel } from 'ui-patterns/IconPanel'
import DocsCoverLogo from './DocsCoverLogo'
const { sdkDart: sdkDartEnabled, sdkKotlin: sdkKotlinEnabled } = isFeatureEnabled([
'sdk:dart',
'sdk:kotlin',
])
function AiPrompt({ className }: { className?: string }) {
return (
<Link
@@ -52,11 +57,13 @@ const HomePageCover = (props) => {
tooltip: 'Flutter',
icon: '/docs/img/icons/flutter-icon',
href: '/guides/getting-started/quickstarts/flutter',
enabled: sdkDartEnabled,
},
{
tooltip: 'Android Kotlin',
icon: '/docs/img/icons/kotlin-icon',
href: '/guides/getting-started/quickstarts/kotlin',
enabled: sdkKotlinEnabled,
},
{
tooltip: 'SvelteKit',
@@ -109,16 +116,18 @@ const HomePageCover = (props) => {
</div>
<div className="shrink-0">
<div className="flex flex-wrap md:grid md:grid-cols-5 gap-2 sm:gap-3">
{frameworks.map((framework, i) => (
<Link key={i} href={framework.href} passHref className="no-underline">
<IconPanel
iconSize={iconSize}
hideArrow
tooltip={framework.tooltip}
icon={framework.icon}
/>
</Link>
))}
{frameworks
.filter((framework) => framework.enabled !== false)
.map((framework, i) => (
<Link key={i} href={framework.href} passHref className="no-underline">
<IconPanel
iconSize={iconSize}
hideArrow
tooltip={framework.tooltip}
icon={framework.icon}
/>
</Link>
))}
</div>
<AiPrompt className="mt-6" />
</div>
@@ -11,6 +11,7 @@ export interface NavMenuSection {
name: string
url?: `/${string}` | `https://${string}`
items: Partial<NavMenuSection>[]
enabled?: boolean
}
type MenuItem = {
@@ -20,6 +21,7 @@ type MenuItem = {
level?: string
hasLightIcon?: boolean
community?: boolean
enabled?: boolean
}
export type DropdownMenuItem = MenuItem & {
@@ -22,7 +22,7 @@ import { GLOBAL_MENU_ITEMS } from './NavigationMenu.constants'
/**
* Get TopNav active label based on current pathname
*/
export const useActiveMenuLabel = (GLOBAL_MENU_ITEMS) => {
export const useActiveMenuLabel = (menu: typeof GLOBAL_MENU_ITEMS) => {
const pathname = usePathname()
const [activeLabel, setActiveLabel] = useState('')
@@ -32,8 +32,10 @@ export const useActiveMenuLabel = (GLOBAL_MENU_ITEMS) => {
return setActiveLabel('Home')
}
for (let index = 0; index < GLOBAL_MENU_ITEMS.length; index++) {
const section = GLOBAL_MENU_ITEMS[index]
for (let index = 0; index < menu.length; index++) {
const section = menu[index]
if (section[0].enabled === false) continue
// check if first level menu items match beginning of url
if (section[0].href?.startsWith(pathname)) {
return setActiveLabel(section[0].label)
@@ -41,13 +43,15 @@ export const useActiveMenuLabel = (GLOBAL_MENU_ITEMS) => {
// check if second level menu items match beginning of url
if (section[0].menuItems) {
section[0].menuItems.map((menuItemGroup) =>
menuItemGroup.map(
(menuItem) => menuItem.href?.startsWith(pathname) && setActiveLabel(section[0].label)
)
menuItemGroup
.filter((menuItem) => menuItem.enabled !== false)
.map(
(menuItem) => menuItem.href?.startsWith(pathname) && setActiveLabel(section[0].label)
)
)
}
}
}, [pathname])
}, [pathname, menu])
return activeLabel
}
@@ -67,65 +71,14 @@ const GlobalNavigationMenu: FC = () => {
viewportClassName="mt-0 max-w-screen overflow-hidden border-0 rounded-none mt-1.5 rounded-md !border-x"
>
<NavigationMenuList className="px-6 space-x-2 h-[var(--header-height)]">
{GLOBAL_MENU_ITEMS.map((section, sectionIdx) =>
section[0].menuItems ? (
<NavigationMenuItem
key={`desktop-docs-menu-section-${section[0].label}-${sectionIdx}`}
className="text-sm relative h-full"
>
<NavigationMenuTrigger
className={cn(
navigationMenuTriggerStyle(),
triggerClassName,
activeLabel === section[0].label && 'text-foreground border-foreground'
)}
{GLOBAL_MENU_ITEMS.filter((section) => section[0].enabled !== false).map(
(section, sectionIdx) =>
section[0].menuItems ? (
<NavigationMenuItem
key={`desktop-docs-menu-section-${section[0].label}-${sectionIdx}`}
className="text-sm relative h-full"
>
{section[0].label === 'Home' ? (
<MenuIconPicker icon={section[0].icon || ''} />
) : (
section[0].label
)}
</NavigationMenuTrigger>
<NavigationMenuContent className="!top-[calc(100%+4px)] min-w-[14rem] max-h-[calc(100vh-4rem)] border-y w-screen md:w-64 overflow-hidden overflow-y-auto rounded-none md:rounded-md md:border border-overlay bg-overlay text-foreground-light shadow-md !duration-0">
<div className="p-3 md:p-1">
{section[0].menuItems?.map((menuItem, menuItemIndex) => (
<Fragment key={`desktop-docs-menu-section-${menuItemIndex}-${menuItemIndex}`}>
{menuItemIndex !== 0 && <MenubarSeparator className="bg-border-muted" />}
{menuItem.map((item, itemIdx) =>
!item.href ? (
<div
key={`desktop-docs-menu-section-label-${item.label}-${itemIdx}`}
className="font-mono tracking-wider flex items-center text-foreground-muted text-xs uppercase rounded-md p-2 leading-none"
>
{item.label}
</div>
) : (
<NavigationMenuLink
key={`desktop-docs-menu-section-label-${item.label}-${itemIdx}`}
asChild
>
<MenuItem
href={item.href}
title={item.label}
community={item.community}
icon={item.icon}
/>
</NavigationMenuLink>
)
)}
</Fragment>
))}
</div>
</NavigationMenuContent>
</NavigationMenuItem>
) : (
<NavigationMenuItem
key={`desktop-docs-menu-section-${section[0].label}-${sectionIdx}`}
className="text-sm relative h-full"
>
<NavigationMenuLink asChild>
<Link
href={section[0].href || '#'}
<NavigationMenuTrigger
className={cn(
navigationMenuTriggerStyle(),
triggerClassName,
@@ -137,10 +90,66 @@ const GlobalNavigationMenu: FC = () => {
) : (
section[0].label
)}
</Link>
</NavigationMenuLink>
</NavigationMenuItem>
)
</NavigationMenuTrigger>
<NavigationMenuContent className="!top-[calc(100%+4px)] min-w-[14rem] max-h-[calc(100vh-4rem)] border-y w-screen md:w-64 overflow-hidden overflow-y-auto rounded-none md:rounded-md md:border border-overlay bg-overlay text-foreground-light shadow-md !duration-0">
<div className="p-3 md:p-1">
{section[0].menuItems?.map((menuItem, menuItemIndex) => (
<Fragment
key={`desktop-docs-menu-section-${menuItemIndex}-${menuItemIndex}`}
>
{menuItemIndex !== 0 && <MenubarSeparator className="bg-border-muted" />}
{menuItem
.filter((item) => item.enabled !== false)
.map((item, itemIdx) =>
!item.href ? (
<div
key={`desktop-docs-menu-section-label-${item.label}-${itemIdx}`}
className="font-mono tracking-wider flex items-center text-foreground-muted text-xs uppercase rounded-md p-2 leading-none"
>
{item.label}
</div>
) : (
<NavigationMenuLink
key={`desktop-docs-menu-section-label-${item.label}-${itemIdx}`}
asChild
>
<MenuItem
href={item.href}
title={item.label}
community={item.community}
icon={item.icon}
/>
</NavigationMenuLink>
)
)}
</Fragment>
))}
</div>
</NavigationMenuContent>
</NavigationMenuItem>
) : (
<NavigationMenuItem
key={`desktop-docs-menu-section-${section[0].label}-${sectionIdx}`}
className="text-sm relative h-full"
>
<NavigationMenuLink asChild>
<Link
href={section[0].href || '#'}
className={cn(
navigationMenuTriggerStyle(),
triggerClassName,
activeLabel === section[0].label && 'text-foreground border-foreground'
)}
>
{section[0].label === 'Home' ? (
<MenuIconPicker icon={section[0].icon || ''} />
) : (
section[0].label
)}
</Link>
</NavigationMenuLink>
</NavigationMenuItem>
)
)}
</NavigationMenuList>
</NavigationMenu>
File diff suppressed because it is too large. Load diff
@@ -94,23 +94,25 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any
{props.subItem.items && props.subItem.items.length > 0 && (
<Accordion.Content className="transition data-open:animate-slide-down data-closed:animate-slide-up ml-2">
{props.subItem.items.map((subSubItem) => {
return (
<li key={props.subItem.name}>
<Link
href={`${subSubItem.url}`}
className={[
'cursor-pointer transition text-sm',
subSubItem.url === pathname
? 'text-brand'
: 'hover:text-brand text-foreground-lighter',
].join(' ')}
>
{subSubItem.name}
</Link>
</li>
)
})}
{props.subItem.items
.filter((subItem) => subItem.enabled !== false)
.map((subSubItem) => {
return (
<li key={props.subItem.name}>
<Link
href={`${subSubItem.url}`}
className={[
'cursor-pointer transition text-sm',
subSubItem.url === pathname
? 'text-brand'
: 'hover:text-brand text-foreground-lighter',
].join(' ')}
>
{subSubItem.name}
</Link>
</li>
)
})}
</Accordion.Content>
)}
</Accordion.Item>
@@ -153,28 +155,32 @@ const Content = (props) => {
</div>
</Link>
{menu.items.map((x) => {
return (
<div key={x.name}>
{x.items && x.items.length > 0 ? (
<div className="flex flex-col gap-2.5">
{x.items.map((subItem, subItemIndex) => {
return (
<ContentAccordionLink
key={subItem.name}
subItem={subItem}
subItemIndex={subItemIndex}
parent={x}
/>
)
})}
</div>
) : x.url ? (
<ContentLink url={x.url} icon={x.icon} name={x.name} key={x.name} />
) : null}
</div>
)
})}
{menu.items
.filter((item) => item.enabled !== false)
.map((x) => {
return (
<div key={x.name}>
{x.items && x.items.length > 0 ? (
<div className="flex flex-col gap-2.5">
{x.items
.filter((item) => item.enabled !== false)
.map((subItem, subItemIndex) => {
return (
<ContentAccordionLink
key={subItem.name}
subItem={subItem}
subItemIndex={subItemIndex}
parent={x}
/>
)
})}
</div>
) : x.url ? (
<ContentLink url={x.url} icon={x.icon} name={x.name} key={x.name} />
) : null}
</div>
)
})}
</ul>
)
}
@@ -0,0 +1,3 @@
## Pricing
For a detailed breakdown of how charges are calculated, refer to [Manage Custom Domain usage](/docs/guides/platform/manage-your-usage/custom-domains).
@@ -0,0 +1,3 @@
## Pricing
For a detailed breakdown of how charges are calculated, refer to [Manage IPv4 usage](/docs/guides/platform/manage-your-usage/ipv4).
@@ -1,2 +1,6 @@
## Pricing
<Price price="0.015" /> per SSO MAU. You are only charged for usage exceeding your subscription plan's
quota.
For a detailed breakdown of how charges are calculated, refer to [Manage Monthly Active SSO Users usage](/docs/guides/platform/manage-your-usage/monthly-active-users-sso).
@@ -1,2 +1,6 @@
## Pricing
<Price price="0.00325" /> per Third-Party MAU. You are only charged for usage exceeding your subscription
plan's quota.
For a detailed breakdown of how charges are calculated, refer to [Manage Monthly Active Third-Party Users usage](/docs/guides/platform/manage-your-usage/monthly-active-users-third-party).
@@ -1,3 +1,5 @@
## Pricing
<Price price="0.1027" /> per hour (<Price price="75" /> per month) for the first project. <Price price="0.0137" /> per
hour (<Price price="10" /> per month) for every additional project.
@@ -6,3 +8,5 @@ hour (<Price price="10" /> per month) for every additional project.
| Pro | <Price price="75" /> | <Price price="10" /> | <Price price="10" /> |
| Team | <Price price="75" /> | <Price price="10" /> | <Price price="10" /> |
| Enterprise | Custom | Custom | Custom |
For a detailed breakdown of how charges are calculated, refer to [Manage Advanced MFA Phone usage](/docs/guides/platform/manage-your-usage/advanced-mfa-phone).
@@ -1,3 +1,5 @@
### Pricing
Pricing depends on the recovery retention period, which determines how many days back you can restore data to any chosen point of up to seconds in granularity.
| Recovery Retention Period in Days | Hourly Price USD | Monthly Price USD |
@@ -5,3 +7,5 @@ Pricing depends on the recovery retention period, which determines how many days
| 7 | <Price price="0.137" /> | <Price price="100" /> |
| 14 | <Price price="0.274" /> | <Price price="200" /> |
| 28 | <Price price="0.55" /> | <Price price="400" /> |
For a detailed breakdown of how charges are calculated, refer to [Manage Point-in-Time Recovery usage](/docs/guides/platform/manage-your-usage/point-in-time-recovery).
@@ -1,3 +1,5 @@
## Pricing
<Price price="5" /> per 1,000 origin images. You are only charged for usage exceeding your subscription
plan's quota.
@@ -12,3 +14,5 @@ The count resets at the start of each billing cycle.
| Pro | 100 | <Price price="5" /> per 1,000 origin images |
| Team | 100 | <Price price="5" /> per 1,000 origin images |
| Enterprise | Custom | Custom |
For a detailed breakdown of how charges are calculated, refer to [Manage Storage Image Transformations usage](/docs/guides/platform/manage-your-usage/storage-image-transformations).
+11
View File
@@ -0,0 +1,11 @@
## Providers
Supabase Auth works with many popular Auth methods, including Social and Phone Auth using third-party providers. See the following sections for a list of supported third-party providers.
### Social Auth
<AuthProviders type="social" />
### Phone Auth
<AuthProviders type="phone" />
@@ -156,6 +156,7 @@ const { data, error } = await supabase.from('todos').select()
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -163,6 +164,8 @@ final data = await supabase.from('todos').select('*');
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -170,6 +173,8 @@ response = supabase.table('todos').select("*").execute()
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -177,4 +182,5 @@ let response = try await supabase.from("todos").select()
```
</TabPanel>
</$Show>
</Tabs>
@@ -57,8 +57,8 @@ const { data: todos, error } = await supabase.schema('myschema').from('todos').s
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
// Initialize the Flutter client
await Supabase.initialize(
@@ -73,9 +73,10 @@ final data = await supabase.from('todos').select();
// You can also change the target schema on a per-query basis
final data = await supabase.schema('myschema').from('todos').select();
```
````
</TabPanel>
</$Show>
<TabPanel id="curl" label="cURL">
```bash
@@ -94,7 +95,7 @@ curl -X POST '<SUPABASE_URL>/rest/v1/todos' \
-H "Content-Type: application/json" \
-H "Content-Profile: myschema" \
-d '{"column_name": "value"}'
```
````
</TabPanel>
</Tabs>
+3 -11
View File
@@ -27,17 +27,9 @@ Auth uses your project's Postgres database under the hood, storing user data and
Auth also enables access control to your database's automatically generated [REST API](/docs/guides/api). When using Supabase SDKs, your data requests are automatically sent with the user's Auth Token. The Auth Token scopes database access on a row-by-row level when used along with [RLS policies](/docs/guides/database/postgres/row-level-security).
## Providers
Supabase Auth works with many popular Auth methods, including Social and Phone Auth using third-party providers. See the following sections for a list of supported third-party providers.
### Social Auth
<AuthProviders type="social" />
### Phone Auth
<AuthProviders type="phone" />
<$Show if="authentication:show_providers">
<$Partial path="providers.mdx" />
</$Show>
## Pricing
@@ -64,6 +64,7 @@ const { data, error } = await supabase.auth.signInAnonymously()
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
Call the [`signInAnonymously()`](/docs/reference/dart/auth-signinanonymously) method:
@@ -73,6 +74,8 @@ await supabase.auth.signInAnonymously();
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Call the [`signInAnonymously()`](/docs/reference/swift/auth-signinanonymously) method:
@@ -82,6 +85,8 @@ let session = try await supabase.auth.signInAnonymously()
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Call the [`signInAnonymously()`](/docs/reference/kotlin/auth-signinanonymously) method:
@@ -91,6 +96,8 @@ supabase.auth.signInAnonymously()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Call the [`sign_in_anonymously()`](/docs/reference/python/auth-signinanonymously) method:
@@ -100,6 +107,7 @@ response = supabase.auth.sign_in_anonymously()
```
</TabPanel>
</$Show>
</Tabs>
## Convert an anonymous user to a permanent user
@@ -138,6 +146,7 @@ const { data: updatePasswordData, error: updatePasswordError } = await supabase.
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
You can use the [`updateUser()`](/docs/reference/dart/auth-updateuser) method to link an email or phone identity to the anonymous user.
@@ -147,6 +156,8 @@ await supabase.auth.updateUser(UserAttributes(email: 'valid.email@supabase.io'))
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You can use the [`updateUser()`](/docs/reference/swift/auth-updateuser) method to link an email or phone identity to the anonymous user.
@@ -158,6 +169,8 @@ try await supabase.auth.updateUser(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
You can use the [`updateUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user.
@@ -169,6 +182,8 @@ supabase.auth.updateUser {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
You can use the [`update_user()`](/docs/reference/python/auth-updateuser) method to link an email or phone identity to the anonymous user. To add a password for the anonymous user, the user's email or phone number needs to be verified first.
@@ -188,6 +203,7 @@ response = supabase.auth.update_user({
```
</TabPanel>
</$Show>
</Tabs>
### Link an OAuth identity
@@ -212,6 +228,7 @@ const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
You can use the [`linkIdentity()`](/docs/reference/dart/auth-linkidentity) method to link an OAuth identity to the anonymous user.
@@ -221,6 +238,8 @@ await supabase.auth.linkIdentity(OAuthProvider.google);
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You can use the [`linkIdentity()`](/docs/reference/swift/auth-linkidentity) method to link an OAuth identity to the anonymous user.
@@ -230,6 +249,8 @@ try await supabase.auth.linkIdentity(provider: .google)
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
You can use the [`linkIdentity()`](/docs/reference/kotlin/auth-linkidentity) method to link an OAuth identity to the anonymous user.
@@ -239,6 +260,8 @@ supabase.auth.linkIdentity(Google)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
You can use the [`link_identity()`](/docs/reference/python/auth-linkidentity) method to link an OAuth identity to the anonymous user.
@@ -248,6 +271,7 @@ response = supabase.auth.link_identity({'provider': 'google'})
```
</TabPanel>
</$Show>
</Tabs>
## Access control
@@ -81,6 +81,7 @@ const { error } = await supabase.auth.signInWithOtp({
Read the [Deep Linking Documentation](/docs/guides/auth/native-mobile-deep-linking) to learn how to handle deep linking.
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -90,6 +91,8 @@ Future<void> signInWithEmail() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -102,6 +105,8 @@ try await supabase.auth.signInWithOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -113,6 +118,8 @@ suspend fun signInWithEmail() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -127,6 +134,7 @@ response = supabase.auth.sign_in_with_otp({
```
</TabPanel>
</$Show>
</Tabs>
{/* supa-mdx-lint-disable-next-line Rule004ExcludeWords */}
@@ -207,6 +215,7 @@ const { data, error } = await supabase.auth.signInWithOtp({
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -216,6 +225,8 @@ Future<void> signInWithEmailOtp() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -227,6 +238,8 @@ try await supabase.auth.signInWithOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -238,6 +251,8 @@ suspend fun signInWithEmailOtp() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -251,6 +266,7 @@ response = supabase.auth.sign_in_with_otp({
```
</TabPanel>
</$Show>
</Tabs>
If the request is successful, you receive a response with `error: null` and a `data` object where both `user` and `session` are null. Let the user know to check their email inbox.
@@ -296,6 +312,7 @@ const {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -307,6 +324,8 @@ try await supabase.auth.verifyOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -314,6 +333,8 @@ supabase.auth.verifyEmailOtp(type = OtpType.Email.EMAIL, email = "email", token
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -325,6 +346,7 @@ response = supabase.auth.verify_otp({
```
</TabPanel>
</$Show>
</Tabs>
If successful, the user is now logged in, and you receive a valid session that looks like:
@@ -42,6 +42,7 @@ const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/dart/auth-linkidentity):
@@ -51,6 +52,8 @@ await supabase.auth.linkIdentity(OAuthProvider.google);
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/swift/auth-linkidentity):
@@ -60,6 +63,8 @@ try await supabase.auth.linkIdentity(provider: .google)
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/kotlin/auth-linkidentity):
@@ -69,6 +74,8 @@ supabase.auth.linkIdentity(Google)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call [`link_identity()`](/docs/reference/python/auth-linkidentity):
@@ -78,6 +85,7 @@ response = supabase.auth.link_identity({'provider': 'google'})
```
</TabPanel>
</$Show>
</Tabs>
In the example above, the user will be redirected to Google to complete the OAuth2.0 flow. Once the OAuth2.0 flow has completed successfully, the user will be redirected back to the application and the Google identity will be linked to the user. You can enable manual linking from your project's authentication [configuration options](/dashboard/project/_/settings/auth) or by setting the environment variable `GOTRUE_SECURITY_MANUAL_LINKING_ENABLED: true` when self-hosting.
@@ -115,6 +123,7 @@ if (!identitiesError) {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
You can use [`getUserIdentities()`](/docs/reference/dart/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/dart/auth-unlinkidentity) to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
@@ -132,6 +141,8 @@ await supabase.auth.unlinkIdentity(googleIdentity);
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You can use [`getUserIdentities()`](/docs/reference/swift/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/swift/auth-unlinkidentity) to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
@@ -148,6 +159,8 @@ try await supabase.auth.unlinkIdentity(googleIdentity)
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
You can use [`currentIdentitiesOrNull()`](/docs/reference/kotlin/auth-getuseridentities) to get all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/kotlin/auth-unlinkidentity) to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
@@ -164,6 +177,8 @@ supabase.auth.unlinkIdentity(googleIdentity.identityId!!)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
You can use [`get_user_identities()`](/docs/reference/python/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlink_identity()`](/docs/reference/python/auth-unlinkidentity) to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
@@ -181,6 +196,7 @@ if google_identity:
```
</TabPanel>
</$Show>
</Tabs>
## Frequently asked questions
@@ -310,8 +310,6 @@ Each code is valid for up to 5 minutes, after which a new one can be sent. Succe
Be aware that Phone MFA is vulnerable to SIM swap attacks where an attacker will call a mobile provider and ask to port the target's phone number to a new SIM card and then use the said SIM card to intercept an MFA code. Evaluate the your application's tolerance for such an attack. You can read more about SIM swapping attacks [here](https://en.wikipedia.org/wiki/SIM_swap_scam)
## Pricing
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_mfa_phone.mdx" />
For a detailed breakdown of how charges are calculated, refer to [Manage Advanced MFA Phone usage](/docs/guides/platform/manage-your-usage/advanced-mfa-phone).
</$Show>
@@ -36,6 +36,7 @@ Error objects are split in a few classes:
Errors originating from the server API classed as `AuthApiError` always have a `code` property that can be used to identify the error returned by the server. The `status` property is also present, encoding the HTTP status code received in the response.
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
All errors originating from the `supabase.auth` namespace of the client library will be wrapped by the `AuthException` class.
@@ -44,12 +45,16 @@ Error objects are split in a few classes. `AuthApiException` is an exception whi
Errors originating from the server API classed as `AuthApiException` always have a `code` property that can be used to identify the error returned by the server. The `statusCode` property is also present, encoding the HTTP status code received in the response.
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
All errors originating from the `supabase.auth` namespace of the client library will be a case of the `AuthError` enum.
The `api(message:errorCode:underlyingData:underlyingResponse:)` case is a special case for errors which originates from the Supabase Auth API, this error always have an `errorCode` property that can be used to identify the error returned by the server.
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
All errors originating from the `supabase.auth` namespace of the client library will be wrapped by the `AuthError` class.
@@ -58,6 +63,8 @@ Error objects are split in a few classes. `AuthApiError` is an error which origi
Errors originating from the server API classed as `AuthApiError` always have a `code` property that can be used to identify the error returned by the server. The `status` property is also present, encoding the HTTP status code received in the response.
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
All exceptions originating from the `supabase.auth` namespace of the Kotlin client library will be a subclass of `RestException`.
@@ -70,6 +77,7 @@ Rest exceptions are split into a few classes:
All instances and subclasses of a `AuthRestException` have a `errorCode` property that can be used to identify the error returned by the server.
</TabPanel>
</$Show>
</Tabs>
@@ -206,6 +206,7 @@ supabase.auth.signInWithSSO({
Calling [`signInWithSSO`](/docs/reference/javascript/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -217,6 +218,8 @@ await supabase.auth.signInWithSSO(
Calling [`signInWithSSO`](/docs/reference/dart/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -228,6 +231,8 @@ try await supabase.auth.signInWithSSO(
Calling [`signInWithSSO`](/docs/reference/swift/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -239,6 +244,7 @@ supabase.auth.signInWith(SSO) {
Calling [`signInWith(SSO)`](/docs/reference/kotlin/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
</TabPanel>
</$Show>
</Tabs>
### Understanding attribute mappings
@@ -384,11 +390,9 @@ supabase sso show <provider-id> --project-ref <your-project>
You can use the `-o json` flag to output the information as JSON, should you need to. Other formats may be supported, use `--help` to see all available options.
## Pricing
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_mau_sso.mdx" />
For a detailed breakdown of how charges are calculated, refer to [Manage Monthly Active SSO Users usage](/docs/guides/platform/manage-your-usage/monthly-active-users-sso).
</$Show>
## Frequently asked questions
+9
View File
@@ -106,6 +106,8 @@ const supabase = createClient(
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
```dart
@@ -120,6 +122,9 @@ await Supabase.initialize(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift (iOS)">
@@ -140,6 +145,9 @@ let supabase = SupabaseClient(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
@@ -155,6 +163,7 @@ val supabase = createSupabaseClient(
```
</TabPanel>
</$Show>
</Tabs>
@@ -85,6 +85,7 @@ const { data, error } = await supabase.auth.signUp({
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -99,6 +100,8 @@ final res = await supabase.auth.signUp(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -113,6 +116,8 @@ try await supabase.auth.signUp(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -127,6 +132,7 @@ val data = supabase.auth.signUpWith(Email) {
```
</TabPanel>
</$Show>
</Tabs>
User metadata is stored on the `raw_user_meta_data` column of the `auth.users` table. To view the metadata:
@@ -152,6 +158,7 @@ let metadata = user?.user_metadata
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -160,6 +167,8 @@ final Map<String, dynamic>? metadata = user?.userMetadata;
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -168,6 +177,8 @@ let metadata = user.userMetadata
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -178,6 +189,7 @@ val metadata = user?.userMetadata
```
</TabPanel>
</$Show>
</Tabs>
## Deleting users
@@ -304,6 +304,8 @@ With Deep Linking, you can configure this redirect to open a specific page. This
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
### Deep link config
@@ -342,6 +344,8 @@ With Deep Linking, you can configure this redirect to open a specific page. This
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Android Kotlin">
### Deep link config
@@ -396,4 +400,5 @@ With Deep Linking, you can configure this redirect to open a specific page. This
The user will now be authenticated when your app receives a valid deep link!
</TabPanel>
</$Show>
</Tabs>
@@ -72,6 +72,7 @@ async function signUpNewUser() {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
To sign up the user, call [signUp()](/docs/reference/dart/auth-signup) with their email address and password:
@@ -86,6 +87,8 @@ Future<void> signUpNewUser() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
To sign up the user, call [signUp()](/docs/reference/swift/auth-signup) with their email address and password.
@@ -103,6 +106,8 @@ let response = try await supabase.auth.signUp(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
To sign up the user, call [signUpWith(Email)](/docs/reference/kotlin/auth-signup) with their email address and password:
@@ -117,6 +122,8 @@ suspend fun signUpNewUser() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
To sign up the user, call [signUp()](/docs/reference/python/auth-signup) with their email address and password.
@@ -136,6 +143,7 @@ data = await supabase.auth.sign_up({
```
</TabPanel>
</$Show>
</Tabs>
</TabPanel>
@@ -409,6 +417,7 @@ async function signUpNewUser() {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
To sign up the user, call [signUp()](/docs/reference/dart/auth-signup) with their email address and password:
@@ -423,6 +432,8 @@ Future<void> signUpNewUser() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
To sign up the user, call [signUp()](/docs/reference/swift/auth-signup) with their email address and password:
@@ -435,6 +446,8 @@ let response = try await supabase.auth.signUp(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
To sign up the user, call [signUpWith(Email)](/docs/reference/kotlin/auth-signup) with their email address and password:
@@ -449,6 +462,8 @@ suspend fun signUpNewUser() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
To sign up the user, call [signUp()](/docs/reference/python/auth-signup) with their email address and password:
@@ -461,6 +476,7 @@ data = supabase.auth.sign_up({
```
</TabPanel>
</$Show>
</Tabs>
</TabPanel>
@@ -493,6 +509,7 @@ async function signInWithEmail() {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
When your user signs in, call [`signInWithPassword()`](/docs/reference/dart/auth-signinwithpassword) with their email address and password:
@@ -507,6 +524,8 @@ Future<void> signInWithEmail() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
When your user signs in, call [signIn(email:password:)](/docs/reference/swift/auth-signinwithpassword) with their email address and password:
@@ -519,6 +538,8 @@ try await supabase.auth.signIn(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Email)](/docs/reference/kotlin/auth-signinwithpassword) with their email address and password:
@@ -533,6 +554,8 @@ suspend fun signInWithEmail() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
When your user signs in, call [sign_in_with_password()](/docs/reference/python/auth-signinwithpassword) with their email address and password:
@@ -545,6 +568,7 @@ data = client.auth.sign_in_with_password({
```
</TabPanel>
</$Show>
</Tabs>
### Resetting a password
@@ -583,6 +607,7 @@ await supabase.auth.resetPasswordForEmail('valid.email@supabase.io', {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -593,6 +618,8 @@ try await supabase.auth.resetPasswordForEmail(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -605,6 +632,8 @@ supabase.auth.resetPasswordForEmail(
If you are on one of the Kotlin targets that have built-in support for redirect URL handling, such as Android, see [OAuth and OTP link verification](https://supabase.com/docs/reference/kotlin/initializing).
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -615,6 +644,7 @@ client.auth.reset_password_email(
```
</TabPanel>
</$Show>
</Tabs>
#### Step 2: Create a change password page
@@ -880,6 +910,7 @@ async function resetPassword() {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -887,6 +918,8 @@ try await supabase.auth.resetPasswordForEmail("valid.email@supabase.io")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -896,6 +929,8 @@ supabase.gotrue.sendRecoveryEmail(
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -903,6 +938,7 @@ supabase.auth.reset_password_email('valid.email@supabase.io')
```
</TabPanel>
</$Show>
</Tabs>
Once you have a session, collect the user's new password and call `updateUser` to update their password.
@@ -929,6 +965,7 @@ await supabase.auth.updateUser({ password: 'new_password' })
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -936,6 +973,8 @@ try await supabase.auth.updateUser(user: UserAttributes(password: newPassword))
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -945,6 +984,8 @@ supabase.auth.updateUser {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -952,6 +993,7 @@ supabase.auth.update_user({'password': 'new_password'})
```
</TabPanel>
</$Show>
</Tabs>
### Email sending
@@ -1022,6 +1064,7 @@ const { data, error } = await supabase.auth.signUp({
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1032,6 +1075,8 @@ try await supabase.auth.signUp(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1042,6 +1087,8 @@ supabase.auth.signUpWith(Phone) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1052,6 +1099,7 @@ supabase.auth.sign_up({
```
</TabPanel>
</$Show>
<TabPanel id="http" label="HTTP">
```bash
@@ -1096,6 +1144,7 @@ const {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyOTP`:
@@ -1109,6 +1158,8 @@ try await supabase.auth.verifyOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyPhoneOtp`:
@@ -1122,6 +1173,8 @@ supabase.auth.verifyPhoneOtp(
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verify_otp`:
@@ -1135,6 +1188,7 @@ supabase.auth.verify_otp({
```
</TabPanel>
</$Show>
<TabPanel id="http" label="HTTP">
```bash
@@ -1176,6 +1230,7 @@ const { data, error } = await supabase.auth.signInWithPassword({
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1186,6 +1241,8 @@ try await supabase.auth.signIn(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1196,6 +1253,8 @@ supabase.auth.signInWith(Phone) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1206,6 +1265,7 @@ supabase.auth.sign_in_with_password({
```
</TabPanel>
</$Show>
<TabPanel id="http" label="HTTP">
```bash
@@ -57,6 +57,7 @@ const { data, error } = await supabase.auth.signInWithOtp({
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -66,6 +67,8 @@ try await supabase.auth.signInWithOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -75,6 +78,8 @@ supabase.auth.signInWith(OTP) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -84,6 +89,7 @@ response = supabase.auth.sign_in_with_otp({
```
</TabPanel>
</$Show>
<TabPanel id="http" label="HTTP">
```bash
@@ -131,6 +137,7 @@ const {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyOTP`:
@@ -144,6 +151,8 @@ try await supabase.auth.verifyOTP(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyPhoneOtp`:
@@ -157,6 +166,8 @@ supabase.auth.verifyPhoneOtp(
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verify_otp`:
@@ -170,6 +181,7 @@ response = supabase.auth.verify_otp({
```
</TabPanel>
</$Show>
<TabPanel id="http" label="HTTP">
```bash
@@ -223,6 +235,7 @@ const { data, error } = await supabase.auth.updateUser({
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -234,6 +247,8 @@ try await supabase.auth.updateUser(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -243,6 +258,8 @@ supabase.auth.updateUser {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -252,6 +269,7 @@ response = supabase.auth.update_user({
```
</TabPanel>
</$Show>
</Tabs>
The user receives an SMS with a 6-digit pin that you must [verify](#verifying-a-phone-otp) within 60 seconds.
+12
View File
@@ -30,6 +30,7 @@ async function signOut() {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -39,6 +40,8 @@ Future<void> signOut() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -46,6 +49,8 @@ try await supabase.auth.signOut()
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -55,6 +60,8 @@ suspend fun logout() {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -62,6 +69,7 @@ supabase.auth.sign_out()
```
</TabPanel>
</$Show>
</Tabs>
## Sign out and scopes
@@ -99,6 +107,7 @@ await supabase.auth.signOut({ scope: 'local' })
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -110,6 +119,8 @@ await supabase.auth.signOut(scope: SignOutScope.global);
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -121,6 +132,7 @@ supabase.auth.signOut(SignOutScope.GLOBAL)
```
</TabPanel>
</$Show>
</Tabs>
Upon sign out, all refresh tokens and potentially other database objects related to the affected sessions are destroyed and the client library removes the session stored in the local storage medium.
@@ -320,6 +320,8 @@ curl -X PATCH "https://api.supabase.com/v1/projects/$PROJECT_REF/config/auth" \
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
## Using native sign in with Apple in Swift
@@ -378,6 +380,9 @@ curl -X PATCH "https://api.supabase.com/v1/projects/$PROJECT_REF/config/auth" \
</Admonition>
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
@@ -419,4 +424,5 @@ curl -X PATCH "https://api.supabase.com/v1/projects/$PROJECT_REF/config/auth" \
```
</TabPanel>
</$Show>
</Tabs>
@@ -180,6 +180,7 @@ Future<void> signInWithAzure() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Azure` as the `Provider`:
@@ -193,6 +194,7 @@ suspend fun signInWithAzure() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -230,6 +232,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -241,6 +244,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Obtain the provider refresh token
@@ -284,6 +288,7 @@ Future<void> signInWithAzure() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -295,6 +300,7 @@ suspend fun signInWithAzure() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -91,6 +91,7 @@ Future<void> signInWithBitbucket() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Bitbucket` as the `Provider`:
@@ -102,6 +103,7 @@ suspend fun signInWithBitbucket() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -142,6 +144,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -153,6 +156,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -108,6 +108,7 @@ Future<void> signInWithDiscord() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Discord` as the `Provider`:
@@ -119,6 +120,7 @@ suspend fun signInWithDiscord() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -161,6 +163,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -172,6 +175,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -171,6 +171,7 @@ Make sure to configure your Facebook app properly and add the required permissio
</Admonition>
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
When your user signs in, call [`signInWithOAuth()`](/docs/reference/swift/auth-signinwithoauth) with `facebook` as the `provider`:
@@ -191,6 +192,8 @@ func signInWithFacebook() async throws {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Facebook` as the `Provider`:
@@ -202,6 +205,7 @@ suspend fun signInWithFacebook() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -239,6 +243,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
When your user signs out, call [signOut()](/docs/reference/swift/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -250,6 +255,8 @@ func signOut() async throws {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -261,6 +268,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
Now, you should be able to login with Facebook and alert you to `Submit for Login Review` when users try to sign into your app. Follow the instructions there to make your app go live for full features and products.
@@ -88,6 +88,7 @@ Future<void> signInWithFigma() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Figma` as the `Provider`:
@@ -99,6 +100,7 @@ suspend fun signInWithFigma() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -136,6 +138,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -147,6 +150,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -103,6 +103,7 @@ Future<void> signInWithGithub() async {
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
When your user signs in, call [`signInWithOAuth`](/docs/reference/swift/auth-signinwithoauth) with `.github` as the `Provider`:
@@ -117,6 +118,8 @@ func signInWithGithub() async throws {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with [`Github`](https://github.com/supabase-community/supabase-kt/blob/master/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/providers/Providers.kt#L16-L20) as the `Provider`:
@@ -128,6 +131,7 @@ suspend fun signInWithGithub() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -168,6 +172,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -179,6 +184,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -88,6 +88,7 @@ Future<void> signInWithGitLab() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Gitlab` as the `Provider`:
@@ -99,6 +100,7 @@ suspend fun signInWithGitLab() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -139,6 +141,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -150,6 +153,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -145,6 +145,8 @@ To use Google's pre-built signin buttons:
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Google sign-in with Supabase is done through the [`GoogleSignIn-iOS`](https://github.com/google/GoogleSignIn-iOS) package.
@@ -189,6 +191,7 @@ To use Google's pre-built signin buttons:
3. Add web client ID and iOS client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_, separated by a comma. Enable the `Skip nonce check` option.
</TabPanel>
</$Show>
<TabPanel id="android" label="Android (Kotlin)">
@@ -112,6 +112,7 @@ Future<void> signInWithKakao() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Kakao` as the `Provider`:
@@ -123,6 +124,7 @@ suspend fun signInWithKakao() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -156,6 +158,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -167,6 +170,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Using Kakao Login JS SDK
@@ -106,6 +106,7 @@ Future<void> signInWithKeycloak() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Keycloak` as the `Provider`:
@@ -119,6 +120,7 @@ suspend fun signInWithKeycloak() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -152,6 +154,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -167,6 +170,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -108,6 +108,7 @@ Future<void> signInWithLinkedIn() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `LinkedIn` as the `Provider`:
@@ -119,6 +120,7 @@ suspend fun signInWithKaLinkedIn() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -156,6 +158,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -167,6 +170,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## LinkedIn Open ID Connect (OIDC)
@@ -88,6 +88,7 @@ Future<void> signInWithNotion() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Notion` as the `Provider`:
@@ -99,6 +100,7 @@ suspend fun signInWithNotion() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -136,6 +138,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -147,6 +150,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -124,6 +124,7 @@ Future<void> signInWithSlack() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `SlackOIDC` as the `Provider`:
@@ -135,6 +136,7 @@ suspend fun signInWithSlack() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -172,6 +174,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -183,6 +186,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -118,6 +118,7 @@ Future<void> signInWithSpotify() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Spotify` as the `Provider`:
@@ -129,6 +130,7 @@ suspend fun signInWithSpotify() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -166,6 +168,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -177,6 +180,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -103,6 +103,7 @@ Future<void> signInWithTwitch() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitch` as the `Provider`:
@@ -114,6 +115,7 @@ suspend fun signInWithTwitch() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -151,6 +153,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -162,6 +165,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -115,6 +115,7 @@ Future<void> signInWithTwitter() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitter` as the `Provider`:
@@ -126,6 +127,7 @@ suspend fun signInWithTwitter() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -166,6 +168,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -177,6 +180,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -119,6 +119,7 @@ Future<void> signInWithZoom() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Zoom` as the `Provider`:
@@ -130,6 +131,7 @@ suspend fun signInWithZoom() {
```
</TabPanel>
</$Show>
</Tabs>
<$Partial path="oauth_pkce_flow.mdx" />
@@ -167,6 +169,7 @@ Future<void> signOut() async {
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
@@ -178,6 +181,7 @@ suspend fun signOut() {
```
</TabPanel>
</$Show>
</Tabs>
## Resources
+9
View File
@@ -49,6 +49,8 @@ const supabase = createClient(
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift (iOS)">
```swift
@@ -73,6 +75,9 @@ let supabase = SupabaseClient(
```
</TabPanel>
</$Show>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
@@ -96,6 +101,9 @@ Future<void> main() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
@@ -114,6 +122,7 @@ val supabase = createSupabaseClient(
```
</TabPanel>
</$Show>
</Tabs>
@@ -43,6 +43,8 @@ Hub.listen('auth', () => {
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift (iOS)">
```swift
@@ -72,6 +74,9 @@ let supabase = SupabaseClient(
```
</TabPanel>
</$Show>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
@@ -96,6 +101,9 @@ Future<void> main() async {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
@@ -128,6 +136,7 @@ suspend fun getAccessToken(): String? {
```
</TabPanel>
</$Show>
</Tabs>
+6
View File
@@ -45,6 +45,8 @@ hideElidedLines={true}
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
```dart
@@ -63,6 +65,9 @@ await Supabase.initialize(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift (iOS)">
@@ -84,6 +89,7 @@ let supabase = SupabaseClient(
```
</TabPanel>
</$Show>
</Tabs>
@@ -40,6 +40,8 @@ Make sure the all users in your application have the `role: 'authenticated'` [cu
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Flutter">
Creating a client for the Web is as easy as passing the `accessToken` async function. This function should [return the Firebase Auth JWT of the current user](https://firebase.google.com/docs/auth/admin/verify-id-tokens) (or null if no such user) is found.
@@ -59,6 +61,9 @@ await Supabase.initialize(
Make sure the all users in your application have the `role: 'authenticated'` [custom claim](https://firebase.google.com/docs/auth/admin/custom-claims) set. If you're using the `onCreate` Cloud Function to add this custom claim to newly signed up users, you will need to call `getIdToken(/* forceRefresh */ true)` immediately after sign up as the `onCreate` function does not run synchronously.
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift (iOS)">
@@ -86,6 +91,9 @@ let supabase = SupabaseClient(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin (Android)">
@@ -106,6 +114,9 @@ val supabase = createSupabaseClient(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlinmp" label="Kotlin (Multiplatform)">
@@ -126,6 +137,7 @@ val supabase = createSupabaseClient(
```
</TabPanel>
</$Show>
</Tabs>
+2 -4
View File
@@ -30,8 +30,6 @@ There are some limitations you should be aware of when using third-party authent
2. The JWT signing keys from the third-party provider are stored in the configuration of your project, and are checked for changes periodically. If you are rotating your keys (when supported) allow up to 30 minutes for the change to be picked up.
3. It is not possible to disable Supabase Auth at this time.
## Pricing
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_mau_third_party.mdx" />
For a detailed breakdown of how charges are calculated, refer to [Manage Monthly Active Third-Party Users usage](/docs/guides/platform/manage-your-usage/monthly-active-users-third-party).
</$Show>
@@ -73,6 +73,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Insert a record from the Swift client:
@@ -97,6 +98,8 @@ try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Insert a record from the Python client:
@@ -114,6 +117,7 @@ supabase.from_('arraytest').insert(
```
</TabPanel>
</$Show>
</Tabs>
## View the results
@@ -204,6 +208,7 @@ returns:
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
This returns the entire array field:
@@ -228,6 +233,7 @@ returns:
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -90,6 +90,7 @@ const { data, error } = supabase.rpc('function_name')
```
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -97,6 +98,7 @@ val data = supabase.postgrest.rpc("function_name")
```
</TabPanel>
</$Show>
</Tabs>
## Examples
@@ -128,6 +128,7 @@ const { error } = await supabase.from('restaurants').insert([
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -148,6 +149,8 @@ await supabase.from('restaurants').insert([
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -168,6 +171,8 @@ try await supabase.from("restaurants")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -187,6 +192,7 @@ val data = supabase.from("restaurants").insert(listOf(
```
</TabPanel>
</$Show>
</Tabs>
Notice the order in which you pass the latitude and longitude. Longitude comes first, and is because longitude represents the x-axis of the location. Another thing to watch for is when inserting data from the client library, there is no comma between the two values, just a single space.
@@ -241,6 +247,7 @@ const { data, error } = await supabase.rpc('nearby_restaurants', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -251,6 +258,8 @@ final data = await supabase.rpc('nearby_restaurants',params: {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -279,6 +288,8 @@ let response: Response = try await supabase.rpc(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -292,6 +303,7 @@ val data = supabase.postgrest.rpc(
```
</TabPanel>
</$Show>
<TabPanel id="result" label="Result">
```json
@@ -367,6 +379,7 @@ const { data, error } = await supabase.rpc('restaurants_in_view', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -379,6 +392,8 @@ final data = await supabase.rpc('restaurants_in_view', params: {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -403,6 +418,8 @@ let response: Response = try await supabase.rpc(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -418,6 +435,7 @@ val data = supabase.postgrest.rpc(
```
</TabPanel>
</$Show>
<TabPanel id="result" label="Result">
```json
@@ -129,6 +129,7 @@ const { data, error } = await supabase.from('books').select().eq('title', 'Harry
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -139,6 +140,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -149,6 +152,8 @@ let response = try await supabase.from("books")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -160,6 +165,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -167,6 +174,7 @@ data = supabase.from_('books').select().eq('title', 'Harry').execute()
```
</TabPanel>
</$Show>
</Tabs>
The equality symbol above (`=`) is very "strict" on what it matches. In a full text search context, we might want to find all "Harry Potter" books and so we can rewrite the
@@ -195,6 +203,7 @@ const { data, error } = await supabase.from('books').select().textSearch('title'
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -205,6 +214,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -214,6 +225,8 @@ let response = try await supabase.from("books")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -225,6 +238,7 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
</Tabs>
## Basic full text queries
@@ -260,6 +274,7 @@ const { data, error } = await supabase.from('books').select().textSearch('descri
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -270,6 +285,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -280,6 +297,8 @@ let response = await client.from("books")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -291,6 +310,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -298,6 +319,7 @@ data = supabase.from_('books').select().text_search('description', "'big'").exec
```
</TabPanel>
</$Show>
<TabPanel id="data" label="Data">
@@ -355,6 +377,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```sql
@@ -371,6 +394,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```sql
@@ -388,6 +413,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```sql
@@ -405,6 +432,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```sql
@@ -418,6 +447,7 @@ data = supabase.from_('books').select().text_search('title_description', "little
```
</TabPanel>
</$Show>
<TabPanel id="data" label="Data">
{/* supa-mdx-lint-disable Rule003Spelling */}
@@ -466,6 +496,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -476,6 +507,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -487,6 +520,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -498,6 +533,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -505,6 +542,7 @@ data = supabase.from_('books').select().text_search('description', "'little' & '
```
</TabPanel>
</$Show>
<TabPanel id="data" label="Data">
{/* supa-mdx-lint-disable Rule003Spelling */}
@@ -552,6 +590,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -562,6 +601,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -573,6 +614,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -584,6 +627,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -591,6 +636,7 @@ response = client.from_('books').select().text_search('description', "'little' |
```
</TabPanel>
</$Show>
<TabPanel id="data" label="Data">
{/* supa-mdx-lint-disable Rule003Spelling */}
@@ -652,6 +698,7 @@ const { data, error } = await supabase.rpc('search_books_by_title_prefix', { pre
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -659,6 +706,8 @@ final data = await supabase.rpc('search_books_by_title_prefix', params: { 'prefi
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -670,6 +719,8 @@ let response = try await supabase.rpc(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -678,6 +729,8 @@ val result = supabase.postgrest.rpc("search_books_by_title_prefix", rpcParams)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -685,6 +738,7 @@ data = client.rpc('search_books_by_title_prefix', { 'prefix': 'Lit' }).execute()
```
</TabPanel>
</$Show>
</Tabs>
This function takes a prefix parameter and returns all books where the title contains a word starting with that prefix. The `:*` operator is used to denote a prefix match in the `to_tsquery()` function.
@@ -777,6 +831,7 @@ const { data, error } = await supabase.from('books').select().textSearch('fts',
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -787,6 +842,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -798,6 +855,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -809,6 +868,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -816,6 +877,7 @@ data = client.from_('books').select().text_search('fts', "'little' & 'big'").exe
```
</TabPanel>
</$Show>
<TabPanel id="data" label="Data">
{/* supa-mdx-lint-disable Rule003Spelling */}
@@ -868,6 +930,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -878,6 +941,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -889,6 +954,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -900,6 +967,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -907,6 +976,7 @@ data = client.from_('books').select().text_search('description', "'big' <-> 'dre
```
</TabPanel>
</$Show>
</Tabs>
We can also use the `<->` to find words within a certain distance of each other. For example to find `year` and `school` within 2 words of each other:
@@ -940,6 +1010,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -950,6 +1021,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -961,6 +1034,8 @@ let response = try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -972,6 +1047,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -979,6 +1056,7 @@ data = client.from_('books').select().text_search('description', "'year' <2> 'sc
```
</TabPanel>
</$Show>
</Tabs>
### Negation: `!` [#negation]
@@ -1015,6 +1093,7 @@ const { data, error } = await supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1025,6 +1104,8 @@ final result = await client
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1036,6 +1117,8 @@ let response = try await client
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1047,6 +1130,8 @@ val data = supabase.from("books").select {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1054,6 +1139,7 @@ data = client.from_('books').select().text_search('description', "'big' & !'litt
```
</TabPanel>
</$Show>
</Tabs>
## Resources
@@ -91,6 +91,7 @@ const { data, error } = await supabase.rpc('hello_world')
Reference: [`rpc()`](../../reference/javascript/rpc)
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -101,6 +102,8 @@ final data = await supabase
Reference: [`rpc()`](../../reference/dart/rpc)
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -110,6 +113,8 @@ try await supabase.rpc("hello_world").execute()
Reference: [`rpc()`](../../reference/swift/rpc)
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -119,6 +124,8 @@ val data = supabase.postgrest.rpc("hello_world")
Reference: [`rpc()`](../../reference/kotlin/rpc)
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -128,6 +135,7 @@ data = supabase.rpc('hello_world').execute()
Reference: [`rpc()`](../../reference/python/rpc)
</TabPanel>
</$Show>
</Tabs>
## Returning data sets
@@ -236,6 +244,7 @@ const { data, error } = supabase.rpc('get_planets').eq('id', 1)
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -245,6 +254,8 @@ final data = await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -252,6 +263,8 @@ let response = try await supabase.rpc("get_planets").eq("id", value: 1).execute(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -263,6 +276,8 @@ val data = supabase.postgrest.rpc("get_planets") {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -270,6 +285,7 @@ data = supabase.rpc('get_planets').eq('id', 1).execute()
```
</TabPanel>
</$Show>
</Tabs>
## Passing parameters
@@ -316,6 +332,7 @@ const { data, error } = await supabase.rpc('add_planet', { name: 'Jakku' })
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -324,6 +341,8 @@ final data = await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Using `Encodable` type:
@@ -351,6 +370,8 @@ try await supabase.rpc(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -363,6 +384,8 @@ val data = supabase.postgrest.rpc(
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -370,6 +393,7 @@ data = supabase.rpc('add_planet', params={'name': 'Jakku'}).execute()
```
</TabPanel>
</$Show>
</Tabs>
## Suggestions
@@ -129,6 +129,7 @@ const sectionsWithInstruments: SectionsWithInstruments = data
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -136,6 +137,8 @@ final data = await supabase.from('orchestral_sections').select('id, name, instru
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -158,6 +161,8 @@ let orchestralSections: [OrchestralSection] = try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -165,6 +170,8 @@ val data = supabase.from("orchestral_sections").select(Columns.raw("id, name, in
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -172,6 +179,7 @@ data = supabase.from_('orchestral_sections').select('id, name, instruments(id, n
```
</TabPanel>
</$Show>
<TabPanel id="graphql" label="GraphQL">
```javascript
@@ -245,6 +253,7 @@ const { data, error } = await supabase.from('teams').select(`
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -252,6 +261,8 @@ final data = await supabase.from('teams').select('id, team_name, users(id, name)
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -284,6 +295,8 @@ let teams [Team] = try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -291,6 +304,8 @@ val data = supabase.from("teams").select(Columns.raw("id, team_name, users(id, n
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -298,6 +313,7 @@ data = supabase.from_('teams').select('id, team_name, users(id, name)').execute(
```
</TabPanel>
</$Show>
<TabPanel id="graphql" label="GraphQL">
````javascript
@@ -396,6 +412,7 @@ const { data, error } = await supabase.from('shifts').select(
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -415,6 +432,8 @@ end_scan:scans!scan_id_end (
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -466,6 +485,9 @@ let shifts: [Shift] = try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
@@ -486,6 +508,8 @@ end_scan:scans!scan_id_end (
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -505,6 +529,7 @@ data = supabase.from_('shifts').select("""
```
</TabPanel>
</$Show>
<TabPanel id="graphql" label="GraphQL">
```javascript
@@ -183,6 +183,7 @@ const { data, error } = await supabase.from('books').insert([
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -237,6 +238,8 @@ await supabase.from('books').insert([
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Supabase Swift provides a convenience `AnyJSON` type.
@@ -301,6 +304,8 @@ try await supabase.from("books")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -330,6 +335,8 @@ val data = supabase.from("books").insert(listOf(
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -384,6 +391,7 @@ supabase.from_('books').insert([
```
</TabPanel>
</$Show>
</Tabs>
## Query JSON data
@@ -425,6 +433,7 @@ const { data, error } = await supabase.from('books').select(`
```
</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -443,6 +452,8 @@ try await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -456,6 +467,8 @@ val data = supabase.from("books").select(Columns.raw("""
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -470,6 +483,7 @@ data = supabase.from_('books').select("""
```
</TabPanel>
</$Show>
<TabPanel id="result" label="Result">
| title | description | price | low_age | high_age |
@@ -226,6 +226,7 @@ const { data, error } = await supabase.from('movies').insert([
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -241,6 +242,8 @@ await supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -263,6 +266,8 @@ try await supabase.from("movies")
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -279,6 +284,8 @@ client.from_("movies").insert([
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -299,6 +306,7 @@ supabase
```
</TabPanel>
</$Show>
</Tabs>
### Bulk data loading
+55 -32
View File
@@ -101,6 +101,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a React app.',
icon: '/docs/img/icons/react-icon',
enabled: true,
},
{
title: 'Next.js',
@@ -109,6 +110,7 @@ hideToc: true
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Next.js app.',
icon: '/docs/img/icons/nextjs-icon',
hasLightIcon: true,
enabled: true,
},
{
title: 'Nuxt',
@@ -116,6 +118,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Nuxt app.',
icon: '/docs/img/icons/nuxt-icon',
enabled: true,
},
{
title: 'Hono',
@@ -123,6 +126,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, secure it with auth, and query the data from a Hono app.',
icon: '/docs/img/icons/hono-icon',
enabled: true,
},
{
title: 'RedwoodJS',
@@ -130,6 +134,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database using Prisma migration and seeds, and query the data from a RedwoodJS app.',
icon: '/docs/img/icons/redwood-icon',
enabled: true,
},
{
title: 'Flutter',
@@ -137,6 +142,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Flutter app.',
icon: '/docs/img/icons/flutter-icon',
enabled: isFeatureEnabled('sdk:dart'),
},
{
title: 'iOS SwiftUI',
@@ -144,6 +150,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from an iOS app.',
icon: '/docs/img/icons/swift-icon',
enabled: isFeatureEnabled('sdk:swift'),
},
{
title: 'Android Kotlin',
@@ -151,6 +158,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from an Android Kotlin app.',
icon: '/docs/img/icons/kotlin-icon',
enabled: isFeatureEnabled('sdk:kotlin'),
},
{
title: 'SvelteKit',
@@ -158,6 +166,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SvelteKit app.',
icon: '/docs/img/icons/svelte-icon',
enabled: true,
},
{
title: 'SolidJS',
@@ -165,6 +174,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SolidJS app.',
icon: '/docs/img/icons/solidjs-icon',
enabled: true,
},
{
title: 'Vue',
@@ -172,6 +182,7 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Vue app.',
icon: '/docs/img/icons/vuejs-icon',
enabled: true,
},
{
title: 'refine',
@@ -179,22 +190,25 @@ hideToc: true
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a refine app.',
icon: '/docs/img/icons/refine-icon',
enabled: true,
},
].map((item) => {
return (
<Link href={`${item.href}`} key={item.title} passHref className={'col-span-4'}>
<GlassPanel
title={item.title}
span="col-span-6"
background={false}
icon={item.icon}
hasLightIcon={item.hasLightIcon}
>
{item.description}
</GlassPanel>
</Link>
)
})}
]
.filter((item) => item.enabled !== false)
.map((item) => {
return (
<Link href={`${item.href}`} key={item.title} passHref className={'col-span-4'}>
<GlassPanel
title={item.title}
span="col-span-6"
background={false}
icon={item.icon}
hasLightIcon={item.hasLightIcon}
>
{item.description}
</GlassPanel>
</Link>
)
})}
</div>
### Web app demos
@@ -208,63 +222,63 @@ hideToc: true
description:
'Learn how to build a user management app with Next.js and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/nextjs-icon',
hasLightIcon: true
hasLightIcon: true,
},
{
title: 'React',
href: '/guides/getting-started/tutorials/with-react',
description:
'Learn how to build a user management app with React and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/react-icon'
icon: '/docs/img/icons/react-icon',
},
{
title: 'Vue 3',
href: '/guides/getting-started/tutorials/with-vue-3',
description:
'Learn how to build a user management app with Vue 3 and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/vuejs-icon'
icon: '/docs/img/icons/vuejs-icon',
},
{
title: 'Nuxt 3',
href: '/guides/getting-started/tutorials/with-nuxt-3',
description:
'Learn how to build a user management app with Nuxt 3 and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/nuxt-icon'
icon: '/docs/img/icons/nuxt-icon',
},
{
title: 'Angular',
href: '/guides/getting-started/tutorials/with-angular',
description:
'Learn how to build a user management app with Angular and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/angular-icon'
icon: '/docs/img/icons/angular-icon',
},
{
title: 'RedwoodJS',
href: '/guides/getting-started/tutorials/with-redwoodjs',
description:
'Learn how to build a user management app with RedwoodJS and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/redwood-icon'
icon: '/docs/img/icons/redwood-icon',
},
{
title: 'Svelte',
href: '/guides/getting-started/tutorials/with-svelte',
description:
'Learn how to build a user management app with Svelte and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/svelte-icon'
icon: '/docs/img/icons/svelte-icon',
},
{
title: 'SvelteKit',
href: '/guides/getting-started/tutorials/with-sveltekit',
description:
'Learn how to build a user management app with SvelteKit and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/svelte-icon'
icon: '/docs/img/icons/svelte-icon',
},
{
title: 'refine',
href: '/guides/getting-started/tutorials/with-refine',
description:
'Learn how to build a user management app with refine and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/refine-icon'
icon: '/docs/img/icons/refine-icon',
}
]
.map((item) => {
@@ -295,7 +309,8 @@ hideToc: true
href: '/guides/getting-started/tutorials/with-flutter',
description:
'Learn how to build a user management app with Flutter and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/flutter-icon'
icon: '/docs/img/icons/flutter-icon',
enabled: isFeatureEnabled('sdk:dart')
},
{
title: 'Expo React Native',
@@ -303,44 +318,52 @@ hideToc: true
description:
'Learn how to build a user management app with Expo React Native and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/expo-icon',
hasLightIcon: true
hasLightIcon: true,
enabled: true
},
{
title: 'Android Kotlin',
href: '/guides/getting-started/tutorials/with-kotlin',
description:
'Learn how to build a product management app with Android and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/kotlin-icon'
icon: '/docs/img/icons/kotlin-icon',
enabled: isFeatureEnabled('sdk:kotlin')
},
{
title: 'iOS Swift',
href: '/guides/getting-started/tutorials/with-swift',
description:
'Learn how to build a user management app with iOS and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/swift-icon'
icon: '/docs/img/icons/swift-icon',
enabled: isFeatureEnabled('sdk:swift')
},
{
title: 'Ionic React',
href: '/guides/getting-started/tutorials/with-ionic-react',
description:
'Learn how to build a user management app with Ionic React and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/ionic-icon'
icon: '/docs/img/icons/ionic-icon',
enabled: true
},
{
title: 'Ionic Vue',
href: '/guides/getting-started/tutorials/with-ionic-vue',
description:
'Learn how to build a user management app with Ionic Vue and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/ionic-icon'
icon: '/docs/img/icons/ionic-icon',
enabled: true
},
{
title: 'Ionic Angular',
href: '/guides/getting-started/tutorials/with-ionic-angular',
description:
'Learn how to build a user management app with Ionic Angular and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/ionic-icon'
icon: '/docs/img/icons/ionic-icon',
enabled: true
}
].map((item) => {
]
.filter((item) => item.enabled !== false)
.map((item) => {
return (
<Link href={`${item.href}`} key={item.title} passHref className={'col-span-4'}>
<GlassPanel
@@ -78,7 +78,7 @@ hideToc: true
<StepHikeCompact.Step step={5}>
<StepHikeCompact.Details title="Query data from the app">
In `App.jsx`, add a `getInstruments` function to fetch the data and display the query result to the page using a Supabase client.
Replace the contents of `App.jsx` to add a `getInstruments` function to fetch the data and display the query result to the page using a Supabase client.
</StepHikeCompact.Details>
<StepHikeCompact.Code>
@@ -120,7 +120,7 @@ hideToc: true
<StepHikeCompact.Step step={6}>
<StepHikeCompact.Details title="Start the app">
Start the app, go to http://localhost:5173 in a browser, and open the browser console and you should see the list of instruments.
Run the development server, go to http://localhost:5173 in a browser and you should see the list of instruments.
</StepHikeCompact.Details>
@@ -163,11 +163,9 @@ A date and time picker will be provided upon pressing the `Start a restore` butt
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.
### Pricing
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_pitr.mdx" />
For a detailed breakdown of how charges are calculated, refer to [Manage Point-in-Time Recovery usage](/docs/guides/platform/manage-your-usage/point-in-time-recovery).
</$Show>
## Restore to a new project
@@ -35,7 +35,7 @@ You may want to consider this option to avoid issues with recurring payments, ga
<Admonition type="note">
If you are interested in larger (> <Price price="1" />,000) credit packages, [reach out](https://supabase.com/dashboard/support/new?subject=I%20would%20like%20to%20inquire%20about%20larger%20credit%20packages&category=Sales).
If you are interested in larger (> <Price price="2000" />) credit packages, [reach out](https://supabase.com/dashboard/support/new?subject=I%20would%20like%20to%20inquire%20about%20larger%20credit%20packages&category=Sales).
</Admonition>
@@ -217,6 +217,6 @@ Use the [`vanity-subdomains delete`](/docs/reference/cli/supabase-vanity-subdoma
supabase vanity-subdomains delete --project-ref abcdefghijklmnopqrst --experimental
```
## Pricing
For a detailed breakdown of how charges are calculated, refer to [Manage Custom Domain usage](/docs/guides/platform/manage-your-usage/custom-domains).
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_custom_domains.mdx" />
</$Show>
@@ -126,6 +126,6 @@ Always uses an IPv4 address
postgresql://postgres.ajrbwkcuthywfddihrmflo:[YOUR-PASSWORD]@aws-0-us-east-1.pooler.supabase.com:5432/postgres
```
## Pricing
For a detailed breakdown of how charges are calculated, refer to [Manage IPv4 usage](/docs/guides/platform/manage-your-usage/ipv4).
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_ipv4.mdx" />
</$Show>
@@ -171,6 +171,7 @@ Then, to join a topic with RLS enabled, instantiate the Channel with the `privat
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
final channel = supabase.channel(
@@ -190,6 +191,8 @@ Then, to join a topic with RLS enabled, instantiate the Channel with the `privat
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
let channel = supabase.channel("room-1") {
@@ -207,6 +210,8 @@ Then, to join a topic with RLS enabled, instantiate the Channel with the `privat
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
val channel = supabase.channel("room-1") {
@@ -220,6 +225,8 @@ Then, to join a topic with RLS enabled, instantiate the Channel with the `privat
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```py
channel = realtime.channel(
@@ -238,6 +245,7 @@ Then, to join a topic with RLS enabled, instantiate the Channel with the `privat
```
</TabPanel>
</$Show>
</Tabs>
#### Allow a user to send a Broadcast message
@@ -33,6 +33,7 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -50,6 +51,8 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -62,6 +65,8 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -73,6 +78,8 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -88,6 +95,7 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
```
</TabPanel>
</$Show>
</Tabs>
### Receiving Broadcast messages
@@ -129,6 +137,7 @@ You can provide a callback for the `broadcast` channel to receive messages. This
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
{/* prettier-ignore */}
@@ -150,6 +159,8 @@ You can provide a callback for the `broadcast` channel to receive messages. This
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -166,6 +177,8 @@ You can provide a callback for the `broadcast` channel to receive messages. This
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
{/* prettier-ignore */}
@@ -182,6 +195,8 @@ You can provide a callback for the `broadcast` channel to receive messages. This
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
<Admonition type="note">
@@ -205,6 +220,7 @@ You can provide a callback for the `broadcast` channel to receive messages. This
```
</TabPanel>
</$Show>
</Tabs>
## Send messages
@@ -260,6 +276,8 @@ You can use the Supabase client libraries to send Broadcast messages.
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
{/* prettier-ignore */}
@@ -287,6 +305,8 @@ You can use the Supabase client libraries to send Broadcast messages.
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
{/* prettier-ignore */}
@@ -307,6 +327,8 @@ You can use the Supabase client libraries to send Broadcast messages.
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
val myChannel = supabase.channel("test-channel") {
@@ -329,6 +351,9 @@ You can use the Supabase client libraries to send Broadcast messages.
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
@@ -356,6 +381,7 @@ You can use the Supabase client libraries to send Broadcast messages.
```
</TabPanel>
</$Show>
</Tabs>
{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
### Broadcast from the Database
@@ -484,6 +510,7 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `self` parameter to `true`.
@@ -512,6 +539,8 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `receiveOwnBroadcasts` parameter to `true`.
@@ -534,6 +563,8 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `receiveOwnBroadcasts` parameter to `true`.
@@ -562,6 +593,8 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
<Admonition type="note">
@@ -595,6 +628,7 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
</Tabs>
### Acknowledge messages
@@ -636,6 +670,7 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -659,6 +694,8 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
You can confirm that Realtime received your message by setting Broadcast's `acknowledgeBroadcasts` config to `true`.
@@ -674,6 +711,8 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `acknowledgeBroadcasts` parameter to `true`.
@@ -691,9 +730,12 @@ You can pass configuration options while initializing the Supabase Client.
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Unsupported in Python yet.
</TabPanel>
</$Show>
</Tabs>
Use this to guarantee that the server has received the message before resolving `channelD.send`'s promise. If the `ack` config is not set to `true` when creating the channel, the promise returned by `channelD.send` will resolve immediately.
@@ -736,6 +778,7 @@ You can also send a Broadcast message by making an HTTP request to Realtime serv
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
// No need to subscribe to channel
@@ -751,6 +794,8 @@ You can also send a Broadcast message by making an HTTP request to Realtime serv
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
let myChannel = await supabase.channel("room-2") {
@@ -763,6 +808,8 @@ You can also send a Broadcast message by making an HTTP request to Realtime serv
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
val myChannel = supabase.channel("room-2") {
@@ -779,9 +826,12 @@ You can also send a Broadcast message by making an HTTP request to Realtime serv
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Unsupported in Python yet.
</TabPanel>
</$Show>
</Tabs>
## Trigger broadcast messages from your database
@@ -238,6 +238,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -252,6 +253,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -272,6 +275,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -293,6 +298,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -305,6 +312,7 @@ changes = supabase.channel('schema-db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
The channel name can be any string except 'realtime'.
@@ -337,6 +345,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -350,6 +359,8 @@ final changes = supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Use `InsertAction.self` as type to listen only to database `INSERT`s:
@@ -367,6 +378,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Use `PostgresAction.Insert` as type to listen only to database `INSERT`s:
@@ -386,6 +399,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -398,6 +413,7 @@ changes = supabase.channel('schema-db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
The channel name can be any string except 'realtime'.
@@ -430,6 +446,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -443,6 +460,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Use `UpdateAction.self` as type to listen only to database `UPDATE`s:
@@ -460,6 +479,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Use `PostgresAction.Update` as type to listen only to database `UPDATE`s:
@@ -479,6 +500,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -491,6 +514,7 @@ changes = supabase.channel('schema-db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
The channel name can be any string except 'realtime'.
@@ -523,6 +547,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -536,6 +561,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Use `DeleteAction.self` as type to listen only to database `DELETE`s:
@@ -553,6 +580,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Use `PostgresAction.Delete` as type to listen only to database `DELETE`s:
@@ -572,6 +601,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -584,6 +615,7 @@ changes = supabase.channel('schema-db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
The channel name can be any string except 'realtime'.
@@ -617,6 +649,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -631,6 +664,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swfit">
<TabPanel id="swift" label="Swift">
```swift
@@ -651,6 +686,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -670,6 +707,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -683,6 +722,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
The channel name can be any string except 'realtime'.
@@ -725,6 +765,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -744,6 +785,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -756,6 +799,8 @@ await myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -770,6 +815,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -787,6 +834,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
### Filtering for specific changes
@@ -819,6 +867,7 @@ const changes = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -838,6 +887,8 @@ const changes = supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -858,6 +909,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -878,6 +931,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -892,6 +947,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
## Available filters
@@ -928,6 +984,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -947,6 +1004,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -967,6 +1026,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -987,6 +1048,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1001,6 +1064,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `=` filter.
@@ -1035,6 +1099,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1054,6 +1119,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1074,6 +1141,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1095,6 +1164,8 @@ myChannel.join()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1109,6 +1180,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `!=` filter.
@@ -1143,6 +1215,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1162,6 +1235,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1182,6 +1257,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1202,6 +1279,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1216,6 +1295,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `<` filter, so it works for non-numeric types. Make sure to check the expected behavior of the compared data's type.
@@ -1250,6 +1330,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1269,6 +1350,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1289,6 +1372,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1309,6 +1394,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1323,6 +1410,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres' `<=` filter, so it works for non-numeric types. Make sure to check the expected behavior of the compared data's type.
@@ -1357,6 +1445,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1376,6 +1465,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1396,6 +1487,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1416,6 +1509,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1430,6 +1525,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `>` filter, so it works for non-numeric types. Make sure to check the expected behavior of the compared data's type.
@@ -1464,6 +1560,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1483,6 +1580,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1503,6 +1602,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1523,6 +1624,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1537,6 +1640,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `>=` filter, so it works for non-numeric types. Make sure to check the expected behavior of the compared data's type.
@@ -1571,6 +1675,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1590,6 +1695,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1610,6 +1717,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1630,6 +1739,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1644,6 +1755,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
This filter uses Postgres's `= ANY`. Realtime allows a maximum of 100 values for this filter.
@@ -1724,6 +1836,7 @@ const channel = supabase
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1746,6 +1859,8 @@ supabase
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1768,6 +1883,8 @@ for await change in changes {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -1793,6 +1910,8 @@ myChannel.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1809,6 +1928,7 @@ changes = supabase.channel('db-changes').on_postgres_changes(
```
</TabPanel>
</$Show>
</Tabs>
### Refreshed tokens
@@ -1833,6 +1953,7 @@ supabase.realtime.setAuth('fresh-token')
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -1840,6 +1961,8 @@ supabase.realtime.setAuth('fresh-token');
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -1847,6 +1970,8 @@ await supabase.realtime.setAuth("fresh-token")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
In Kotlin, you have to update the token manually per channel:
@@ -1856,6 +1981,8 @@ myChannel.updateAuth("fresh-token")
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -1863,6 +1990,7 @@ supabase.realtime.set_auth('fresh-token')
```
</TabPanel>
</$Show>
</Tabs>
## Limitations
@@ -33,6 +33,7 @@ const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -49,6 +50,8 @@ final supabase = Supabase.instance.client;
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -60,6 +63,8 @@ let realtime = supabase.realtime
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -71,6 +76,8 @@ val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -83,6 +90,7 @@ supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
```
</TabPanel>
</$Show>
</Tabs>
### Sync and track state
@@ -120,6 +128,7 @@ roomOne
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -138,6 +147,8 @@ roomOne.onPresenceSync((_) {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
Listen to the presence change stream, emitting a new `PresenceAction` whenever someone joins or leaves:
@@ -155,6 +166,8 @@ for await presence in presenceStream {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Listen to the presence change flow, emitting new a new `PresenceAction` whenever someone joins or leaves:
@@ -173,6 +186,8 @@ roomOne.subscribe()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
Listen to the `sync`, `join`, and `leave` events triggered whenever any client joins or leaves the channel or changes their slice of state:
@@ -188,6 +203,7 @@ room_one
```
</TabPanel>
</$Show>
</Tabs>
### Sending state
@@ -225,6 +241,7 @@ roomOne.subscribe(async (status) => {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -244,6 +261,8 @@ roomOne.subscribe((status, error) async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -269,6 +288,8 @@ await roomOne.track(
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -285,6 +306,8 @@ roomOne.track(userStatus)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -305,6 +328,7 @@ room_one.subscribe(on_subscribe)
```
</TabPanel>
</$Show>
</Tabs>
A client will receive state from any other client that is subscribed to the same topic (in this case `room_01`). It will also automatically trigger its own `sync` and `join` event handlers.
@@ -337,6 +361,7 @@ untrackPresence()
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -351,6 +376,8 @@ untrackPresence();
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -358,6 +385,8 @@ await roomOne.untrack()
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -369,6 +398,8 @@ untrackPresence()
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -376,6 +407,7 @@ room_one.untrack()
```
</TabPanel>
</$Show>
</Tabs>
## Presence options
@@ -409,6 +441,7 @@ const channelC = supabase.channel('test', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -419,6 +452,8 @@ final channelC = supabase.channel(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -428,6 +463,8 @@ let channelC = await supabase.channel("test") {
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -439,6 +476,8 @@ val channelC = supabase.channel("test") {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -452,4 +491,5 @@ channel_c = supabase.channel('test', {
```
</TabPanel>
</$Show>
</Tabs>
@@ -52,6 +52,7 @@ values
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -67,6 +68,8 @@ void main() async {
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -79,6 +82,8 @@ try await supabase.storage.createBucket(
[Reference.](/docs/reference/swift/storage-createbucket)
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -91,6 +96,7 @@ supabase.storage.create_bucket(
[Reference.](/docs/reference/python/storage-createbucket)
</TabPanel>
</$Show>
</Tabs>
## Restricting uploads
@@ -72,6 +72,7 @@ const { data, error } = await supabase.storage.createBucket('avatars')
[Reference.](/docs/reference/javascript/storage-createbucket)
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -87,6 +88,8 @@ void main() async {
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -96,6 +99,8 @@ try await supabase.storage.createBucket("avatars")
[Reference.](/docs/reference/swift/storage-createbucket)
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -105,6 +110,7 @@ response = supabase.storage.create_bucket('avatars')
[Reference.](/docs/reference/python/storage-createbucket)
</TabPanel>
</$Show>
</Tabs>
## Upload a file
@@ -138,6 +144,7 @@ const { data, error } = await supabase.storage
[Reference.](/docs/reference/javascript/storage-from-upload)
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -157,6 +164,7 @@ void main() async {
[Reference.](https://pub.dev/documentation/storage_client/latest/storage_client/SupabaseStorageClient/createBucket.html)
</TabPanel>
</$Show>
</Tabs>
## Download a file
@@ -189,6 +197,7 @@ const { data, error } = await supabase.storage.from('avatars').download('public/
[Reference.](/docs/reference/javascript/storage-from-download)
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -205,6 +214,8 @@ void main() async {
[Reference.](/docs/reference/dart/storage-from-download)
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -214,6 +225,8 @@ let response = try await supabase.storage.from("avatars").download(path: "public
[Reference.](/docs/reference/python/storage-from-download)
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -223,6 +236,7 @@ response = supabase.storage.from_('avatars').download('public/avatar1.png')
[Reference.](/docs/reference/python/storage-from-download)
</TabPanel>
</$Show>
</Tabs>
## Add security rules
@@ -42,6 +42,7 @@ supabase.storage.from('bucket').getPublicUrl('image.jpg', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -55,6 +56,8 @@ final url = supabase.storage.from('bucket').getPublicUrl(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -66,6 +69,8 @@ let url = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -75,6 +80,8 @@ val url = supabase.storage.from("bucket").publicRenderUrl("image.jpg") {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -90,6 +97,7 @@ url = supabase.storage.from_('avatars').get_public_url(
```
</TabPanel>
</$Show>
</Tabs>
An example URL could look like this:
@@ -125,6 +133,7 @@ supabase.storage.from('bucket').createSignedUrl('image.jpg', 60000, {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -139,6 +148,8 @@ final url = await supabase.storage.from('bucket').createSignedUrl(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -154,6 +165,8 @@ let url = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -163,6 +176,7 @@ val url = supabase.storage.from("bucket").createSignedUrl("image.jpg", 60.second
```
</TabPanel>
</$Show>
</Tabs>
The transformation options are embedded into the token attached to the URL — they cannot be changed once signed.
@@ -194,6 +208,7 @@ supabase.storage.from('bucket').download('image.jpg', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -207,6 +222,8 @@ final data = await supabase.storage.from('bucket').download(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -221,6 +238,8 @@ let data = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -240,6 +259,8 @@ supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -253,6 +274,7 @@ response = supabase.storage.from_('bucket').download(
```
</TabPanel>
</$Show>
</Tabs>
## Automatic image optimization (WebP)
@@ -295,6 +317,7 @@ await supabase.storage.from('bucket').download('image.jpeg', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -309,6 +332,8 @@ final data = await supabase.storage.from('bucket').download(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -324,6 +349,8 @@ let data = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -345,6 +372,8 @@ supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -361,6 +390,7 @@ response = supabase.storage.from_('bucket').download(
```
</TabPanel>
</$Show>
</Tabs>
## Next.js loader
@@ -430,6 +460,7 @@ supabase.storage.from('bucket').download('image.jpg', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -442,6 +473,8 @@ final data = await supabase.storage.from('bucket').download(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -455,6 +488,8 @@ let data = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -474,6 +509,8 @@ supabase.storage["bucket"].downloadAuthenticatedTo("image.jpg", file) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -488,6 +525,7 @@ response = supabase.storage.from_('bucket').download(
```
</TabPanel>
</$Show>
</Tabs>
### Resizing
@@ -532,6 +570,7 @@ supabase.storage.from('bucket').download('image.jpg', {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -546,6 +585,8 @@ final data = supabase.storage.from('bucket').download(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -561,6 +602,8 @@ let data = try await supabase.storage.from("bucket")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -582,6 +625,8 @@ supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -598,6 +643,7 @@ response = supabase.storage.from_('bucket').download(
```
</TabPanel>
</$Show>
</Tabs>
### Limits
@@ -621,11 +667,9 @@ response = supabase.storage.from_('bucket').download(
| BMP | `bmp` | ☑️ | ☑️ |
| TIFF | `tiff` | ☑️ | ☑️ |
## Pricing
<$Show if="billing:all">
<$Partial path="billing/pricing/pricing_storage_image_transformations.mdx" />
For a detailed breakdown of how charges are calculated, refer to [Manage Storage Image Transformations usage](/docs/guides/platform/manage-your-usage/storage-image-transformations).
</$Show>
## Self hosting
@@ -191,6 +191,8 @@ Instead of `https://project-id.supabase.co` use `https://project-id.storage.supa
</TabPanel>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
Kotlin supports resumable uploads natively for all targets:
@@ -222,6 +224,9 @@ Instead of `https://project-id.supabase.co` use `https://project-id.storage.supa
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="py" label="Python">
@@ -269,6 +274,7 @@ Instead of `https://project-id.supabase.co` use `https://project-id.storage.supa
```
</TabPanel>
</$Show>
</Tabs>
### Upload URL
@@ -48,6 +48,7 @@ async function uploadFile(file) {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -58,6 +59,8 @@ Future<void> uploadFile(File file) async {
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -70,6 +73,8 @@ try await supabase.storage.from("bucket_name").upload(path: "file_path", file: f
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -80,6 +85,8 @@ supabase.storage.from("bucket_name").upload("file_path", file)
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -87,6 +94,7 @@ response = supabase.storage.from_('bucket_name').upload('file_path', file)
```
</TabPanel>
</$Show>
</Tabs>
## Overwriting files
@@ -117,6 +125,7 @@ await supabase.storage.from('bucket_name').upload('file_path', file, {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -128,6 +137,8 @@ await supabase.storage.from('bucket_name').upload(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -147,6 +158,8 @@ try await supabase.storage.from("bucket_name")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -156,6 +169,8 @@ supabase.storage.from("bucket_name").upload("file_path", bytes) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -165,6 +180,7 @@ response = supabase.storage.from_('bucket_name').upload('file_path', file, {
```
</TabPanel>
</$Show>
</Tabs>
We do advise against overwriting files when possible, as our Content Delivery Network will take sometime to propagate the changes to all the edge nodes leading to stale content.
@@ -197,6 +213,7 @@ await supabase.storage.from('bucket_name').upload('file_path', file, {
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
@@ -208,6 +225,8 @@ await supabase.storage.from('bucket_name').upload(
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
@@ -227,6 +246,8 @@ try await supabase.storage.from("bucket_name")
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
@@ -236,6 +257,8 @@ supabase.storage.from("bucket_name").upload("file_path", bytes) {
```
</TabPanel>
</$Show>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">
```python
@@ -245,6 +268,7 @@ response = supabase.storage.from_('bucket_name').upload('file_path', file, {
```
</TabPanel>
</$Show>
</Tabs>
## Concurrency
+1
View File
@@ -65,6 +65,7 @@ function toFilePath(node: MdxJsxFlowElement) {
if (typeof path !== 'string' || !isMdFile(path)) {
throw new Error('Invalid $Partial path: path must end with .mdx or .md')
}
const filePath = join(PARTIALS_DIRECTORY, path)
if (!filePath.startsWith(PARTIALS_DIRECTORY)) {
throw new Error(`Invalid $Partial path: Path must be inside ${PARTIALS_DIRECTORY}`)
+199
View File
@@ -0,0 +1,199 @@
import { mdxToMarkdown } from 'mdast-util-mdx'
import { toMarkdown } from 'mdast-util-to-markdown'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { type Feature } from 'common'
import { showRemark } from './Show'
import { fromDocsMarkdown } from './utils.server'
// Mock the isFeatureEnabled function from common package
vi.mock('common/enabled-features', () => ({
isFeatureEnabled: vi.fn(),
}))
const { isFeatureEnabled } = await import('common/enabled-features')
describe('$Show', () => {
beforeEach(() => {
vi.clearAllMocks()
})
afterEach(() => {
vi.restoreAllMocks()
})
it('should keep children and remove $Show wrapper when feature is enabled', async () => {
vi.mocked(isFeatureEnabled).mockReturnValue(true)
const markdown = `
# Test content
<$Show if="test-feature">
This content should be visible when feature is enabled.
## A nested heading
Some more content.
</$Show>
Content after the show block.
`.trim()
const mdast = fromDocsMarkdown(markdown)
const transformed = showRemark()(mdast)
const output = toMarkdown(transformed, { extensions: [mdxToMarkdown()] })
const expected = `
# Test content
This content should be visible when feature is enabled.
## A nested heading
Some more content.
Content after the show block.
`.trimStart()
expect(output).toEqual(expected)
expect(isFeatureEnabled).toHaveBeenCalledWith('test-feature')
})
it('should remove entire $Show block and children when feature is disabled', async () => {
vi.mocked(isFeatureEnabled).mockReturnValue(false)
const markdown = `
# Test content
<$Show if="disabled-feature">
This content should NOT be visible when feature is disabled.
## This heading should also be removed
Some more content that should be hidden.
</$Show>
Content after the show block should remain.
`.trim()
const mdast = fromDocsMarkdown(markdown)
const transformed = showRemark()(mdast)
const output = toMarkdown(transformed, { extensions: [mdxToMarkdown()] })
const expected = `
# Test content
Content after the show block should remain.
`.trimStart()
expect(output).toEqual(expected)
expect(isFeatureEnabled).toHaveBeenCalledWith('disabled-feature')
})
it('should handle multiple $Show blocks with different feature flags', async () => {
vi.mocked(isFeatureEnabled).mockImplementation((feature) => {
if (feature === ('enabled-feature' as Feature)) return true
return false
})
const markdown = `
# Test content
<$Show if="enabled-feature">
This should be visible.
</$Show>
<$Show if="disabled-feature">
This should be hidden.
</$Show>
<$Show if="another-disabled-feature">
This should also be hidden.
</$Show>
Final content.
`.trim()
const mdast = fromDocsMarkdown(markdown)
const transformed = showRemark()(mdast)
const output = toMarkdown(transformed, { extensions: [mdxToMarkdown()] })
const expected = `
# Test content
This should be visible.
Final content.
`.trimStart()
expect(output).toEqual(expected)
expect(isFeatureEnabled).toHaveBeenCalledWith('enabled-feature')
expect(isFeatureEnabled).toHaveBeenCalledWith('disabled-feature')
expect(isFeatureEnabled).toHaveBeenCalledWith('another-disabled-feature')
})
it('should handle nested $Show blocks correctly', async () => {
vi.mocked(isFeatureEnabled).mockImplementation((feature) => {
if (feature === ('outer-feature' as Feature)) return true
return false
})
const markdown = `
# Test content
<$Show if="outer-feature">
Outer content visible.
<$Show if="inner-feature">
Inner content should be hidden.
</$Show>
More outer content.
</$Show>
`.trim()
const mdast = fromDocsMarkdown(markdown)
const transformed = showRemark()(mdast)
const output = toMarkdown(transformed, { extensions: [mdxToMarkdown()] })
const expected = `
# Test content
Outer content visible.
More outer content.
`.trimStart()
expect(output).toEqual(expected)
expect(isFeatureEnabled).toHaveBeenCalledWith('outer-feature')
expect(isFeatureEnabled).toHaveBeenCalledWith('inner-feature')
})
it('should throw error when "if" attribute is missing', () => {
const markdown = `
<$Show>
Content without if attribute.
</$Show>
`.trim()
const mdast = fromDocsMarkdown(markdown)
expect(() => {
showRemark()(mdast)
}).toThrow('$Show directive requires a string value for the "if" attribute')
})
it('should throw error when "if" attribute is not a string', () => {
const markdown = `
<$Show if={true}>
Content with non-string if attribute.
</$Show>
`.trim()
const mdast = fromDocsMarkdown(markdown)
expect(() => {
showRemark()(mdast)
}).toThrow('$Show directive requires a string value for the "if" attribute')
})
})
+72
View File
@@ -0,0 +1,72 @@
/**
* The Show directive supports conditional rendering of content based on feature flags.
* It uses the isFeatureEnabled function from the common package to determine whether
* the content should be displayed.
*
* If the feature is enabled, the <$Show> tag is stripped but its children remain.
* If the feature is disabled, both the <$Show> tag and its children are removed.
*
* ## Examples
*
* ### Basic usage
*
* ```mdx
* <$Show if="feature-name">
* This content will only show if the feature is enabled.
* </$Show>
* ```
*/
import { type Root } from 'mdast'
import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx'
import { type Parent } from 'unist'
import { visitParents } from 'unist-util-visit-parents'
import { isFeatureEnabled, type Feature } from 'common/enabled-features'
import { getAttributeValue } from './utils.server'
export function showRemark() {
return function transform(tree: Root) {
const nodesToProcess = [] as Array<{
node: MdxJsxFlowElement
parent: Parent
shouldShow: boolean
}>
// Collect all $Show nodes and determine their visibility
visitParents(tree, 'mdxJsxFlowElement', (node: MdxJsxFlowElement, ancestors) => {
if (node.name !== '$Show') return
const parent = ancestors[ancestors.length - 1]
const featureName = getAttributeValue(node, 'if')
if (typeof featureName !== 'string') {
throw new Error('$Show directive requires a string value for the "if" attribute')
}
const shouldShow = isFeatureEnabled(featureName as Feature)
nodesToProcess.push({
node,
parent,
shouldShow,
})
})
// Process nodes in reverse order to avoid index shifting issues
for (let i = nodesToProcess.length - 1; i >= 0; i--) {
const { node, parent, shouldShow } = nodesToProcess[i]
const nodeIndex = parent.children.indexOf(node)
if (shouldShow) {
// Feature is enabled: remove the $Show wrapper but keep children
parent.children.splice(nodeIndex, 1, ...node.children)
} else {
// Feature is disabled: remove the entire $Show element and its children
parent.children.splice(nodeIndex, 1)
}
}
return tree
}
}
+2
View File
@@ -10,6 +10,7 @@ import { codeSampleRemark } from './CodeSample'
import { codeTabsRemark } from './CodeTabs'
import { fromDocsMarkdown } from './utils.server'
import { partialsRemark } from './Partial'
import { showRemark } from './Show'
type Transformer = (ast: Root) => Root | Promise<Root>
@@ -27,6 +28,7 @@ export async function preprocessMdx<T>(mdx: string, transformers: Transformer[])
export function preprocessMdxWithDefaults(mdx: string) {
return preprocessMdx(mdx, [
showRemark(),
remarkMkDocsAdmonition(),
remarkPyMdownTabs(),
partialsRemark(),
+2
View File
@@ -4,6 +4,7 @@ import rehypeKatex from 'rehype-katex'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import { isFeatureEnabled } from 'common'
import { preprocessMdxWithDefaults } from '~/features/directives/utils'
import { components } from '~/features/docs/MdxBase.shared'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
@@ -39,6 +40,7 @@ const MDXRemoteBase = async ({
} = mdxOptions
const finalOptions = {
scope: { isFeatureEnabled },
...mdxOptions,
...otherOptions,
mdxOptions: {
+2
View File
@@ -31,6 +31,7 @@ Chris Martin
Chris Stockton
Chris Ward
Craig Cannon
Cuong Do
Danny White
Darren Cunningham
Dave Wilson
@@ -111,6 +112,7 @@ Riccardo Busetti
Rodrigo Mansueli
Ronan Lehane
Rory Wilding
Sam Meech-Ward
Sam Rose
Sean Oliver
Sergio Cioban Filho
-54
View File
@@ -196,12 +196,6 @@
"slug": "v1-apply-a-migration",
"type": "operation"
},
{
"id": "v1-create-restore-point",
"title": "Create restore point",
"slug": "v1-create-restore-point",
"type": "operation"
},
{
"id": "v1-disable-readonly-mode-temporarily",
"title": "Disable readonly mode temporarily",
@@ -256,12 +250,6 @@
"slug": "v1-get-readonly-mode-status",
"type": "operation"
},
{
"id": "v1-get-restore-point",
"title": "Get restore point",
"slug": "v1-get-restore-point",
"type": "operation"
},
{
"id": "v1-get-ssl-enforcement-config",
"title": "Get ssl enforcement config",
@@ -310,12 +298,6 @@
"slug": "v1-setup-a-read-replica",
"type": "operation"
},
{
"id": "v1-undo",
"title": "Undo",
"slug": "v1-undo",
"type": "operation"
},
{
"id": "v1-update-pooler-config",
"title": "Update pooler config",
@@ -538,12 +520,6 @@
"slug": "v1-exchange-oauth-token",
"type": "operation"
},
{
"id": "v1-oauth-authorize-project-claim",
"title": "Oauth authorize project claim",
"slug": "v1-oauth-authorize-project-claim",
"type": "operation"
},
{
"id": "v1-revoke-token",
"title": "Revoke token",
@@ -556,12 +532,6 @@
"type": "category",
"title": "Organizations",
"items": [
{
"id": "v1-claim-project-for-organization",
"title": "Claim project for organization",
"slug": "v1-claim-project-for-organization",
"type": "operation"
},
{
"id": "v1-create-an-organization",
"title": "Create an organization",
@@ -574,12 +544,6 @@
"slug": "v1-get-an-organization",
"type": "operation"
},
{
"id": "v1-get-organization-project-claim",
"title": "Get organization project claim",
"slug": "v1-get-organization-project-claim",
"type": "operation"
},
{
"id": "v1-list-all-organizations",
"title": "List all organizations",
@@ -610,12 +574,6 @@
"slug": "v1-create-a-project",
"type": "operation"
},
{
"id": "v1-create-project-claim-token",
"title": "Create project claim token",
"slug": "v1-create-project-claim-token",
"type": "operation"
},
{
"id": "v1-delete-a-project",
"title": "Delete a project",
@@ -628,12 +586,6 @@
"slug": "v1-delete-network-bans",
"type": "operation"
},
{
"id": "v1-delete-project-claim-token",
"title": "Delete project claim token",
"slug": "v1-delete-project-claim-token",
"type": "operation"
},
{
"id": "v1-get-network-restrictions",
"title": "Get network restrictions",
@@ -658,12 +610,6 @@
"slug": "v1-get-project",
"type": "operation"
},
{
"id": "v1-get-project-claim-token",
"title": "Get project claim token",
"slug": "v1-get-project-claim-token",
"type": "operation"
},
{
"id": "v1-get-services-health",
"title": "Get services health",
@@ -41,6 +41,12 @@ function extractSectionsFromOpenApi(filePath, outputPath) {
for (const route in openApiJson.paths) {
const methods = openApiJson.paths[route]
for (const method in methods) {
// We are using `x-internal` to hide endpoints from the docs,
// but still have them included in the spec so they generate types and can be used.
if (methods[method]['x-internal']) {
continue
}
const tag = methods[method].tags?.[0]
const operationId = methods[method].operationId
// If operationId is not in the form of a slug ignore it.
+1 -1
View File
@@ -1341,7 +1341,7 @@ functions:
isSpotlight: true
code: |
```dart
// retrieve all identites linked to a user
// retrieve all identities linked to a user
final identities = await supabase.auth.getUserIdentities();
// find the google identity
+1 -1
View File
@@ -1625,7 +1625,7 @@ functions:
isSpotlight: true
code: |
```js
// retrieve all identites linked to a user
// retrieve all identities linked to a user
const identities = await supabase.auth.getUserIdentities()
// find the google identity
+1 -1
View File
@@ -1550,7 +1550,7 @@ functions:
isSpotlight: true
code: |
```python
# retrieve all identites linked to a user
# retrieve all identities linked to a user
response = supabase.auth.get_user_identities()
# find the google identity
+1 -1
View File
@@ -944,7 +944,7 @@ functions:
isSpotlight: true
code: |
```swift
// retrieve all identites linked to a user
// retrieve all identities linked to a user
let identities = try await supabase.auth.userIdentities()
// find the google identity
+1 -1
View File
@@ -21,7 +21,7 @@ NEXT_PUBLIC_GOTRUE_URL=$SUPABASE_PUBLIC_URL/auth/v1
NEXT_PUBLIC_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001
# CmdK / AI
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhndWloeHV6cWlid3hqbmlteGV2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzUwOTQ4MzUsImV4cCI6MTk5MDY3MDgzNX0.0PMlOxtKL4O9GGZuAP_Xl4f-Tut1qOnW4bNEmAtoB8w
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhndWloeHV6cWlid3hqbmlteGV2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTgzNzc1MTgsImV4cCI6MjAzMzk1MzUxOH0.aIqjQ9V7djMxYit-DT1fYNV_VWMHSqldh_18XfX2_BE
NEXT_PUBLIC_SUPABASE_URL=https://xguihxuzqibwxjnimxev.supabase.co
DOCKER_SOCKET_LOCATION=/var/run/docker.sock
+4 -4
View File
@@ -13,9 +13,9 @@ import { useTableEditorStateSnapshot } from 'state/table-editor'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
import { Shortcuts } from './components/common/Shortcuts'
import Footer from './components/footer/Footer'
import { Footer } from './components/footer/Footer'
import { Grid } from './components/grid/Grid'
import Header, { HeaderProps } from './components/header/Header'
import { Header, HeaderProps } from './components/header/Header'
import { RowContextMenu } from './components/menu'
import { GridProps } from './types'
@@ -84,7 +84,7 @@ export const SupabaseGrid = ({
return (
<DndProvider backend={HTML5Backend} context={window}>
<div className="sb-grid h-full flex flex-col">
<Header customHeader={customHeader} />
<Header customHeader={customHeader} isRefetching={isRefetching} />
{children || (
<>
@@ -99,7 +99,7 @@ export const SupabaseGrid = ({
filters={filters}
onApplyFilters={onApplyFilters}
/>
<Footer isRefetching={isRefetching} />
<Footer />
<Shortcuts gridRef={gridRef} rows={rows} />
</>
)}
@@ -5,14 +5,9 @@ import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
import { isTableLike, isViewLike } from 'data/table-editor/table-editor-types'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useUrlState } from 'hooks/ui/useUrlState'
import RefreshButton from '../header/RefreshButton'
import { Pagination } from './pagination'
export interface FooterProps {
isRefetching?: boolean
}
const Footer = ({ isRefetching }: FooterProps) => {
export const Footer = () => {
const { id: _id } = useParams()
const id = _id ? Number(_id) : undefined
const { data: project } = useSelectedProjectQuery()
@@ -41,10 +36,6 @@ const Footer = ({ isRefetching }: FooterProps) => {
{selectedView === 'data' && <Pagination />}
<div className="ml-auto flex items-center gap-x-2">
{entity && selectedView === 'data' && (
<RefreshButton tableId={entity.id} isRefetching={isRefetching} />
)}
{(isViewSelected || isTableSelected) && (
<TwoOptionToggle
width={75}
@@ -58,5 +49,3 @@ const Footer = ({ isRefetching }: FooterProps) => {
</GridFooter>
)
}
export default Footer
@@ -8,7 +8,7 @@ import { toast } from 'sonner'
import { useParams } from 'common'
import { useTableFilter } from 'components/grid/hooks/useTableFilter'
import { useTableSort } from 'components/grid/hooks/useTableSort'
import GridHeaderActions from 'components/interfaces/TableGridEditor/GridHeaderActions'
import { GridHeaderActions } from 'components/interfaces/TableGridEditor/GridHeaderActions'
import { formatTableRowsToSQL } from 'components/interfaces/TableGridEditor/TableEntity.utils'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query'
@@ -56,9 +56,10 @@ export const MAX_EXPORT_ROW_COUNT_MESSAGE = (
export type HeaderProps = {
customHeader: ReactNode
isRefetching: boolean
}
const Header = ({ customHeader }: HeaderProps) => {
export const Header = ({ customHeader, isRefetching }: HeaderProps) => {
const snap = useTableEditorTableStateSnapshot()
return (
@@ -71,14 +72,12 @@ const Header = ({ customHeader }: HeaderProps) => {
) : (
<DefaultHeader />
)}
<GridHeaderActions table={snap.originalTable} />
<GridHeaderActions table={snap.originalTable} isRefetching={isRefetching} />
</div>
</div>
)
}
export default Header
const DefaultHeader = () => {
const { ref: projectRef } = useParams()
const { data: org } = useSelectedOrganizationQuery()
@@ -2,15 +2,15 @@ import { useQueryClient } from '@tanstack/react-query'
import { RefreshCw } from 'lucide-react'
import { useParams } from 'common'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { tableRowKeys } from 'data/table-rows/keys'
import { Button } from 'ui'
export type RefreshButtonProps = {
tableId?: number
isRefetching?: boolean
}
const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
export const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
const { ref } = useParams()
const queryClient = useQueryClient()
const queryKey = tableRowKeys.tableRowsAndCount(ref, tableId)
@@ -20,14 +20,18 @@ const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
}
return (
<Button
type="text"
<ButtonTooltip
type="outline"
loading={isRefetching}
icon={<RefreshCw className="text-foreground-muted" strokeWidth={1.5} />}
icon={<RefreshCw />}
onClick={() => onClick()}
>
Refresh
</Button>
className="w-7 h-7 p-0"
tooltip={{
content: {
side: 'bottom',
text: 'Refresh table data',
},
}}
/>
)
}
export default RefreshButton
@@ -8,7 +8,7 @@ import { toast } from 'sonner'
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import AlertError from 'components/ui/AlertError'
import APIDocsButton from 'components/ui/APIDocsButton'
import { APIDocsButton } from 'components/ui/APIDocsButton'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { FilterPopover } from 'components/ui/FilterPopover'
import { FormHeader } from 'components/ui/Forms/FormHeader'
@@ -1,6 +1,6 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { useQueryClient } from '@tanstack/react-query'
import { DollarSign, GitMerge, Github, Loader2 } from 'lucide-react'
import { DatabaseZap, DollarSign, GitMerge, Github, Loader2 } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
@@ -21,6 +21,7 @@ import { useBranchCreateMutation } from 'data/branches/branch-create-mutation'
import { useBranchesQuery } from 'data/branches/branches-query'
import { useCheckGithubBranchValidity } from 'data/integrations/github-branch-check-query'
import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query'
import { useCloneBackupsQuery } from 'data/projects/clone-query'
import { projectKeys } from 'data/projects/keys'
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
@@ -45,6 +46,9 @@ import {
Input_Shadcn_,
Label_Shadcn_ as Label,
Switch,
Tooltip,
TooltipContent,
TooltipTrigger,
cn,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
@@ -59,6 +63,9 @@ export const CreateBranchModal = () => {
const gitlessBranching = useIsBranching2Enabled()
const allowDataBranching = useFlag('allowDataBranching')
// [Joshen] This is meant to be short lived while we're figuring out how to control
// requests to this endpoint. Kill switch in case we need to stop the requests
const disableBackupsCheck = useFlag('disableBackupsCheckInCreatebranchmodal')
const isProPlanAndUp = selectedOrg?.plan?.id !== 'free'
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
@@ -85,6 +92,17 @@ export const CreateBranchModal = () => {
useCheckGithubBranchValidity({
onError: () => {},
})
const { data: cloneBackups, error: cloneBackupsError } = useCloneBackupsQuery(
{ projectRef },
{
// [Joshen] Only trigger this request when the modal is opened
enabled: showCreateBranchModal && !disableBackupsCheck,
}
)
const targetVolumeSizeGb = cloneBackups?.target_volume_size_gb ?? 0
const noPhysicalBackups = cloneBackupsError?.message.startsWith(
'Physical backups need to be enabled'
)
const { mutate: sendEvent } = useSendEventMutation()
@@ -172,6 +190,7 @@ export const CreateBranchModal = () => {
resolver: zodResolver(FormSchema),
defaultValues: { branchName: '', gitBranchName: '', withData: false },
})
const withData = form.watch('withData')
const canSubmit = !isCreating && !isChecking
const isDisabled =
@@ -344,9 +363,22 @@ export const CreateBranchModal = () => {
layout="flex-row-reverse"
description="Clone production data into this branch"
>
<FormControl_Shadcn_>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl_Shadcn_>
<Tooltip>
<TooltipTrigger>
<FormControl_Shadcn_>
<Switch
disabled={!disableBackupsCheck && noPhysicalBackups}
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl_Shadcn_>
</TooltipTrigger>
{!disableBackupsCheck && noPhysicalBackups && (
<TooltipContent side="bottom">
PITR is required for the project to clone data into the branch
</TooltipContent>
)}
</Tooltip>
</FormItemLayout>
)}
/>
@@ -362,6 +394,30 @@ export const CreateBranchModal = () => {
promptProPlanUpgrade && 'opacity-25 pointer-events-none'
)}
>
{withData && (
<div className="flex flex-row gap-4">
<div>
<figure className="w-10 h-10 rounded-md bg-info-200 border border-info-400 flex items-center justify-center">
<DatabaseZap className="text-info" size={20} strokeWidth={2} />
</figure>
</div>
<div className="flex flex-col gap-y-1">
<p className="text-sm text-foreground">
Data branch takes longer time to create
</p>
<p className="text-sm text-foreground-light">
Since your target database volume size is{' '}
<code className="text-xs font-mono">{targetVolumeSizeGb} GB</code>, creating a
data branch is estimated to take around{' '}
<code className="text-xs font-mono">
{Math.round((720 / 21000) * targetVolumeSizeGb) + 3} minutes
</code>
.
</p>
</div>
</div>
)}
{githubConnection && (
<div className="flex flex-row gap-4">
<div>
@@ -9,6 +9,7 @@ import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/dat
import { useSchemasQuery } from 'data/database/schemas-query'
import { executeSql } from 'data/sql/execute-sql-query'
import { useIsOrioleDb, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useProtectedSchemas } from 'hooks/useProtectedSchemas'
import {
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
@@ -43,6 +44,7 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
},
{ enabled: visible }
)
const { data: protectedSchemas } = useProtectedSchemas({ excludeSchemas: ['extensions'] })
const { mutate: enableExtension, isLoading: isEnabling } = useDatabaseExtensionEnableMutation({
onSuccess: () => {
toast.success(`Extension "${extension.name}" is now enabled`)
@@ -180,19 +182,26 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
Create a new schema "{extension.name}"
</Listbox.Option>
<Modal.Separator />
{schemas?.map((schema) => {
return (
<Listbox.Option
key={schema.id}
id={schema.name}
label={schema.name}
value={schema.name}
addOnBefore={() => <Database size={16} strokeWidth={1.5} />}
>
{schema.name}
</Listbox.Option>
{schemas
?.filter(
(schema) =>
!protectedSchemas.some(
(protectedSchema) => protectedSchema.name === schema.name
)
)
})}
.map((schema) => {
return (
<Listbox.Option
key={schema.id}
id={schema.name}
label={schema.name}
value={schema.name}
addOnBefore={() => <Database size={16} strokeWidth={1.5} />}
>
{schema.name}
</Listbox.Option>
)
})}
</Listbox>
)}
</Modal.Content>
@@ -193,6 +193,7 @@ export const ExtensionRow = ({ extension }: ExtensionRowProps) => {
confirmLabel="Disable"
variant="destructive"
confirmLabelLoading="Disabling"
loading={isDisabling}
onCancel={() => setIsDisableModalOpen(false)}
onConfirm={() => onConfirmDisable()}
>
Loaded 100 of 261 files, more files were not shown because too many files have changed in this diff. Show more