Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/docs/content/_partials/metrics_access.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ className="rounded-lg border border-foreground/10 bg-surface-100 text-foreground
3. Authenticate with HTTP Basic Auth:

- **Username**: `service_role`
- **Password**: a service role secret (JWT) from [**Project Settings > JWT**](/dashboard/project/_/settings/jwt) or any other Secret API key from [**Project Settings > API keys** (opens in a new tab)](/dashboard/project/_/settings/api-keys)
- **Password**: a **Secret API key** (`sb_secret_...`). You can create/copy it in [**Project Settings → API Keys**](/dashboard/project/_/settings/api-keys). For more context, see [Understanding API keys](/docs/guides/api/api-keys).

Testing locally is as simple as running `curl` with your service role secret:
Testing locally is as simple as running `curl` with your Secret API key:

```bash
curl <project-url>/customer/v1/privileged/metrics \
Expand All @@ -35,7 +35,7 @@ className="rounded-lg border border-foreground/10 bg-surface-100 text-foreground
You can provision long-lived automation tokens in two ways:

- Create an account access token once at [**Account Settings > Access Tokens**](/dashboard/account/tokens) and reuse it wherever you configure observability tooling.
- **Optional**: programmatically exchange an access token for project API keys via the [Management API ](/docs/reference/api/management-projects-api-keys-retrieve').
- **Optional**: programmatically exchange an access token for project API keys via the [Management API](/docs/reference/api/management-projects-api-keys-retrieve).

```bash
# (Optional) Exchange an account access token for project API keys
Expand Down
26 changes: 26 additions & 0 deletions apps/docs/content/guides/auth/social-login/auth-twitter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ Future<void> signInWithX() async {
```

</TabPanel>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">

When your user signs in, call [`signInWithOAuth(provider:)`](/docs/reference/swift/auth-signinwithoauth) with `.x` as the `provider`:

```swift
func signInWithX() async throws {
try await supabase.auth.signInWithOAuth(provider: .x)
}
```

</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">

Expand Down Expand Up @@ -173,6 +186,19 @@ 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:

```swift
func signOut() async throws {
try await supabase.auth.signOut()
}
```

</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">

Expand Down
8 changes: 7 additions & 1 deletion apps/docs/content/guides/database/replication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ You might use database replication for:

## Replication methods

Supabase supports two methods for replicating your database to external destinations:
Supabase supports three methods for replicating your database to external destinations:

### Read Replicas

Additional databases that are kept in sync with your Primary database. These read-only databases can be deployed across multiple regions, for lower latency and better resource management.

- [Set up Read Replicas](/docs/guides/platform/read-replicas)

### Replication

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ hideToc: true

<StepHikeCompact.Details title="Install the Supabase client library">

Install Supabase package dependency using Xcode by following Apple's [tutorial](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
Add the [supabase-swift](https://github.com/supabase/supabase-swift) package to your app using the Swift Package Manager.

Make sure to add `Supabase` product package as dependency to the application.
In Xcode, navigate to **File > Add Package Dependencies...** and enter the repository URL `https://github.com/supabase/supabase-swift` in the search bar. For detailed instructions, see Apple's [tutorial on adding package dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).

Make sure to add `Supabase` product package as a dependency to your application target.

</StepHikeCompact.Details>

Expand Down Expand Up @@ -76,7 +78,7 @@ hideToc: true

<StepHikeCompact.Code>

```swift name=Supabase.swift
```swift name=Instrument.swift
struct Instrument: Decodable, Identifiable {
let id: Int
let name: String
Expand All @@ -100,6 +102,8 @@ hideToc: true
<StepHikeCompact.Code>

```swift name=ContentView.swift
import SwiftUI

struct ContentView: View {

@State var instruments: [Instrument] = []
Expand Down Expand Up @@ -138,3 +142,12 @@ hideToc: true
</StepHikeCompact.Step>

</StepHikeCompact>

## Setting up deep links

If you want to implement authentication features like magic links or OAuth, you need to set up deep links to redirect users back to your app. For instructions on configuring custom URL schemes for your iOS app, see the [deep linking guide](/docs/guides/auth/native-mobile-deep-linking?platform=swift).

## Next steps

- Learn how to build a complete user management app with authentication in the [Swift tutorial](/docs/guides/getting-started/tutorials/with-swift)
- Explore the [supabase-swift](https://github.com/supabase/supabase-swift) library on GitHub
46 changes: 46 additions & 0 deletions apps/docs/content/guides/storage/debugging/error-codes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,52 @@ subtitle: 'Learn about the Storage error codes and how to resolve them'
sidebar_label: 'Debugging'
---

## Handling Storage errors in SDKs

When using the Supabase SDKs, storage errors provide detailed information to help you debug issues:

<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">

```js
try {
const { data, error } = await supabase.storage.from('avatars').download('avatar.png')

if (error) {
// Access error details
console.log('Error code:', error.error)
console.log('Error message:', error.message)
console.log('HTTP status:', error.status)
console.log('Status code:', error.statusCode)
}
} catch (err) {
console.error('Unexpected error:', err)
}
```

</TabPanel>
<$Show if="sdk:python">
<TabPanel id="python" label="Python">

```python
try:
response = supabase.storage.from_('avatars').download('avatar.png')
except Exception as error:
# Access error details
print(f'Error: {error}')
# The SDK now handles bad responses from the server gracefully
```

</TabPanel>
</$Show>
</Tabs>

## Storage error codes

<Admonition type="note">
Expand Down
65 changes: 65 additions & 0 deletions apps/docs/content/guides/storage/serving/downloads.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,71 @@ If you want the browser to start an automatic download of the asset instead of t

By default it will use the asset name to save the file on disk. You can optionally pass a custom name to the `download` parameter as following: `?download=customname.jpg`

#### Programmatic downloads with query parameters

When using the SDK's `download()` method, you can pass additional query parameters to customize the download behavior:

<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">

```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('your_project_url', 'your_supabase_api_key')

// ---cut---
// Download with custom filename
const { data, error } = await supabase.storage.from('avatars').download('avatar1.png', {
download: 'my-custom-name.png',
})
```

</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">

```dart
// Download with additional query parameters
final response = await supabase.storage
.from('avatars')
.download(
'avatar1.png',
queryParams: {
'download': 'my-custom-name.png',
},
);
```

[Reference.](/docs/reference/dart/storage-from-download)

</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">

```swift
// Download with additional query parameters
let response = try await supabase.storage
.from("avatars")
.download(
path: "avatar1.png",
queryItems: [
URLQueryItem(name: "download", value: "my-custom-name.png")
]
)
```

[Reference.](/docs/reference/swift/storage-from-download)

</TabPanel>
</$Show>
</Tabs>

## Private buckets

Assets stored in a non-public bucket are considered private and are not accessible via a public URL like the public buckets.
Expand Down
8 changes: 4 additions & 4 deletions apps/docs/content/guides/telemetry/metrics/grafana-cloud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Grafana maintains a [Supabase integration guide](https://grafana.com/docs/grafan

## Prerequisites

- A Supabase project with access to the Metrics API (service role key or another secret key).
- A Supabase project with access to the Metrics API (Secret API key `sb_secret_...`).
- A Grafana Cloud account with Prometheus metrics enabled (Free or Pro tier).
- A Grafana API token with the `metrics:write` and `metrics:read` scopes if you plan to push data manually.

Expand All @@ -31,7 +31,7 @@ Grafana maintains a [Supabase integration guide](https://grafana.com/docs/grafan
2. Provide:
- Your Supabase project ref (e.g. `abcd1234`).
- The Metrics API endpoint: `https://<project-ref>.supabase.co/customer/v1/privileged/metrics`.
- HTTP Basic Auth credentials (`service_role` / `service_role key`).
- HTTP Basic Auth credentials (`service_role` / `sb_secret_...`).
3. Choose the scrape interval (1 minute recommended) and test the connection. Grafana Cloud will deploy an agent in the background that scrapes the Metrics API and forwards the data to Prometheus.

If you prefer to reuse an existing Grafana Agent deployment, configure an [integration pipeline](https://grafana.com/docs/grafana-cloud/send-data/agent/integrations/integration-reference/integration-supabase/) with the same URL and credentials.
Expand All @@ -56,6 +56,6 @@ The [`docs/example-alerts.md`](https://github.com/supabase/supabase-grafana/blob

## 5. Troubleshooting

- Metrics missing? Ensure the Grafana Cloud agent can reach `https://<project-ref>.supabase.co` and that the selected service role key is still valid.
- 401 errors? Rotate the service role key from the [API settings page](/dashboard/project/_/settings/api-keys) and update the Grafana Cloud credentials.
- Metrics missing? Ensure the Grafana Cloud agent can reach `https://<project-ref>.supabase.co` and that the selected Secret API key is still valid.
- 401 errors? Create/rotate a Secret API key in [Project Settings → API Keys](/dashboard/project/_/settings/api-keys) and update the Grafana Cloud credentials.
- Long scrape durations? Reduce label cardinality in your Grafana queries or lower the time range to focus on recent data.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ scrape_configs:
scheme: https
basic_auth:
username: service_role
password: '<service-role key or JWT>'
password: '<secret API key (sb_secret_...)>'
static_configs:
- targets:
- '<project-ref>.supabase.co:443'
Expand All @@ -44,7 +44,7 @@ scrape_configs:

- Keep the scrape interval at 60 seconds to match Supabase’s refresh cadence.
- If you run Prometheus behind a proxy, make sure it can establish outbound HTTPS connections to `*.supabase.co`.
- Store secrets (service role key) with your secret manager or inject them via environment variables.
- Store secrets (Secret API key) with your secret manager or inject them via environment variables.

</Admonition>

Expand Down Expand Up @@ -79,4 +79,4 @@ You now have over 200 production-ready panels covering CPU, IO, WAL, replication

- **Multiple projects:** add one scrape job per project ref so you can separate metrics and labels cleanly.
- **Right-sizing guidance:** pair the dashboards with Supabase’s [Query Performance report](/dashboard/project/_/observability/query-performance) and [Advisors](/dashboard/project/_/observability/database) to decide when to optimize vs upgrade.
- **Security:** rotate the service role key on a regular cadence and update the Prometheus config accordingly.
- **Security:** rotate Secret API keys on a regular cadence and update the Prometheus config accordingly.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ No matter which collector you use, you need to hit the Metrics API once per minu
scheme: https
basic_auth:
username: service_role
password: '<service-role key or JWT>'
password: '<secret API key (sb_secret_...)>'
static_configs:
- targets:
- '<project-ref>.supabase.co:443'
Expand All @@ -41,9 +41,9 @@ No matter which collector you use, you need to hit the Metrics API once per minu

## 2. Secure the credentials

- Store the service role key in your secret manager (AWS Secrets Manager, GCP Secret Manager, Vault, etc.).
- Rotate the key periodically via [Project Settings → API keys](/dashboard/project/_/settings/api-keys) and update your collector.
- If you need to give observability vendors access without exposing the service role key broadly, create a dedicated service key for metrics-only automation.
- Store the Secret API key in your secret manager (AWS Secrets Manager, GCP Secret Manager, Vault, etc.).
- Rotate the key periodically via [Project Settings → API Keys](/dashboard/project/_/settings/api-keys) and update your collector.
- If you need to give observability vendors access without exposing a broadly-scoped key, create a dedicated Secret API key for metrics-only automation.

## 3. Downstream dashboards

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This guide is for identifying configuration mistakes in [self-hosted Supabase Gr
Use the below cURL command to make sure your metrics endpoint returns data:

```sh
curl https://<YOUR_PROJECT_REF>.supabase.co/customer/v1/privileged/metrics --user 'service_role:<SERVICE_ROLE_KEY>'
curl https://<YOUR_PROJECT_REF>.supabase.co/customer/v1/privileged/metrics --user 'service_role:<SECRET_API_KEY>'
```

## Step 2: Set your Grafana Dashboard to auto-refresh in the top right corner
Expand Down
5 changes: 1 addition & 4 deletions apps/studio/.github/eslint-rule-baselines.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"react-hooks/exhaustive-deps": 216,
"import/no-anonymous-default-export": 57,
"@tanstack/query/exhaustive-deps": 14,
"@typescript-eslint/no-explicit-any": 1294
"@typescript-eslint/no-explicit-any": 1291
},
"ruleFiles": {
"react-hooks/exhaustive-deps": {
Expand Down Expand Up @@ -350,8 +350,6 @@
"components/interfaces/HomeNew/ProjectUsageSection.tsx": 1,
"components/interfaces/Integrations/CronJobs/CreateCronJobSheet/CreateCronJobSheet.tsx": 1,
"components/interfaces/Integrations/CronJobs/CronJobTableCell.tsx": 2,
"components/interfaces/Integrations/CronJobs/CronJobs.utils.tsx": 1,
"components/interfaces/Integrations/CronJobs/CronJobsTab.tsx": 1,
"components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx": 2,
"components/interfaces/Integrations/GraphQL/GraphiQLTab.tsx": 1,
"components/interfaces/Integrations/Landing/Integrations.constants.tsx": 1,
Expand Down Expand Up @@ -744,7 +742,6 @@
"pages/project/[ref]/api/index.tsx": 3,
"pages/project/[ref]/auth/templates/[templateId].tsx": 1,
"pages/project/[ref]/functions/[functionSlug]/index.tsx": 3,
"pages/project/[ref]/merge.tsx": 1,
"pages/project/[ref]/settings/log-drains.tsx": 1,
"pages/project/[ref]/storage/files/buckets/[bucketId].tsx": 1,
"state/ai-assistant-state.tsx": 4,
Expand Down
14 changes: 11 additions & 3 deletions apps/studio/components/interfaces/App/AppBannerWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { partition } from 'lodash'
import { PropsWithChildren } from 'react'

import { MaintenanceBanner } from '@/components/layouts/AppLayout/MaintenanceBanner'
import { useIncidentStatusQuery } from '@/data/platform/incident-status-query'
import { useFlag } from 'common'
import { ClockSkewBanner } from 'components/layouts/AppLayout/ClockSkewBanner'
Expand All @@ -8,19 +10,25 @@ import { NoticeBanner } from 'components/layouts/AppLayout/NoticeBanner'
import { OrganizationResourceBanner } from '../Organization/HeaderBanner'

export const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => {
const { data: incidents } = useIncidentStatusQuery()
const { data: allStatusPageEvents } = useIncidentStatusQuery()
const [maintenanceEvents, incidents] = partition(
allStatusPageEvents ?? [],
(event) => event.impact === 'maintenance'
)

const ongoingIncident =
useFlag('ongoingIncident') ||
process.env.NEXT_PUBLIC_ONGOING_INCIDENT === 'true' ||
(incidents?.length ?? 0) > 0
incidents.length > 0
const ongoingMaintenance = maintenanceEvents.length > 0

const showNoticeBanner = useFlag('showNoticeBanner')
const clockSkewBanner = useFlag('clockSkewBanner')

return (
<div className="flex flex-col">
<div className="flex-shrink-0">
{ongoingIncident && <IncidentBanner />}
{ongoingIncident ? <IncidentBanner /> : ongoingMaintenance ? <MaintenanceBanner /> : null}
{showNoticeBanner && <NoticeBanner />}
<OrganizationResourceBanner />
{clockSkewBanner && <ClockSkewBanner />}
Expand Down
Loading
Loading