mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 06:09:08 +03:00
Merge master resolve conflicts
This commit is contained in:
commit
f94adf2b0f
792 files changed
+31917
-23117
No files matched your search
@@ -0,0 +1,6 @@
|
||||
---
|
||||
description:
|
||||
globs: apps/studio/**/*.test.ts,apps/studio/**/*.test.tsx
|
||||
alwaysApply: false
|
||||
---
|
||||
Make sure to follow the guidelines in this file to write tests: [README.md](mdc:apps/studio/tests/README.md)
|
||||
@@ -24,9 +24,12 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
test:
|
||||
# Uses larger hosted runner as it significantly decreases build times
|
||||
runs-on: [larger-runner-4cpu]
|
||||
strategy:
|
||||
matrix:
|
||||
test_number: [1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -50,5 +53,25 @@ jobs:
|
||||
env:
|
||||
# Default is 2 GB, increase to have less frequent OOM errors
|
||||
NODE_OPTIONS: '--max_old_space_size=3072'
|
||||
run: pnpm run test:studio
|
||||
working-directory: ./
|
||||
run: pnpm run test:ci
|
||||
working-directory: ./apps/studio
|
||||
|
||||
- name: Upload coverage results to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
parallel: true
|
||||
flag-name: studio-tests
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ./apps/studio/coverage/lcov.info
|
||||
base-path: './apps/studio'
|
||||
|
||||
finish:
|
||||
needs: test
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
parallel-finished: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -15,8 +15,11 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
test_number: [1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -39,4 +42,25 @@ jobs:
|
||||
run: pnpm i
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm run test:ui
|
||||
run: pnpm run test:ci
|
||||
working-directory: ./packages/ui
|
||||
|
||||
- name: Upload coverage results to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
parallel: true
|
||||
flag-name: ui-tests
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ./packages/ui/coverage/lcov.info
|
||||
base-path: './packages/ui'
|
||||
|
||||
finish:
|
||||
needs: test
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
parallel-finished: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -133,3 +133,8 @@ gcloud.json
|
||||
# sitemaps
|
||||
# apps/www/public/*.xml
|
||||
# apps/docs/public/*.xml
|
||||
|
||||
# CLI version file
|
||||
.temp/cli-latest
|
||||
|
||||
.pnpm-store/*
|
||||
@@ -81,7 +81,7 @@ Used for actions that might have a side effect, but not as serious as a destruct
|
||||
|
||||
#### Destructive (currently `danger`)
|
||||
|
||||
Used for actions that will have a serios destructive side effect, like deleting data.
|
||||
Used for actions that will have a serious destructive side effect, like deleting data.
|
||||
|
||||
prop `type` will probably be changed to `destructive` in the future.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ function app() {
|
||||
If you don't need the Collapsible features, you can instead use `<InnerSideBarTitle />`.
|
||||
This doesn't require the use of the `<InnerSideMenuCollapsible />` parent component wrapped around it.
|
||||
|
||||
You can wrap the `<InnerSideBarItem />` conponents however you like. Below we've put a `<div/ >` around them.
|
||||
You can wrap the `<InnerSideBarItem />` components however you like. Below we've put a `<div/ >` around them.
|
||||
|
||||
```jsx {1}
|
||||
<InnerSideBarTitle>Projects</InnerSideBarTitle>
|
||||
@@ -125,7 +125,7 @@ Use the `actions` prop to add any actions like a `<Button />`.
|
||||
/>
|
||||
```
|
||||
|
||||
You can also use the prop `illustration` to pass in a custom illustration, it accets any React Node.
|
||||
You can also use the prop `illustration` to pass in a custom illustration, it accepts any React Node.
|
||||
|
||||
```jsx {4-7}
|
||||
<InnerSideBarEmptyPanel
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"autoprefixer": "^10.0.1",
|
||||
"config": "workspace:^",
|
||||
"mdast-util-toc": "^6.1.1",
|
||||
"postcss": "^8",
|
||||
"postcss": "^8.5.3",
|
||||
"rimraf": "^4.1.3",
|
||||
"shiki": "^1.1.7",
|
||||
"tailwindcss": "^3.3.0",
|
||||
|
||||
@@ -20,6 +20,7 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
**/__generated__/**/*
|
||||
**/*/generated/**/*
|
||||
!**/*/generated/.gitkeep
|
||||
!**/*/generated/**/.gitkeep
|
||||
|
||||
@@ -157,9 +157,7 @@ async function functionDetails(
|
||||
return fullDescription + parameters + examples
|
||||
}
|
||||
|
||||
function mdxToHtml(markdownUnescaped: string): string {
|
||||
const markdown = markdownUnescaped.replace(/(?<!\\)\{/g, '\\{').replace(/(?<!\\)\}/g, '\\}')
|
||||
|
||||
function mdxToHtml(markdown: string): string {
|
||||
const mdast = fromMarkdown(markdown, {
|
||||
extensions: [mdxjs()],
|
||||
mdastExtensions: [mdxFromMarkdown()],
|
||||
|
||||
@@ -5,8 +5,149 @@ exports[`/api/graphql schema snapshot > should match snapshot 1`] = `
|
||||
query: RootQueryType
|
||||
}
|
||||
|
||||
"""
|
||||
A document containing content from the Supabase docs. This is a guide, which might describe a concept, or explain the steps for using or implementing a feature.
|
||||
"""
|
||||
type Guide implements SearchResult {
|
||||
"""The title of the document"""
|
||||
title: String
|
||||
|
||||
"""The URL of the document"""
|
||||
href: String
|
||||
|
||||
"""
|
||||
The full content of the document, including all subsections (both those matching and not matching any query string) and possibly more content
|
||||
"""
|
||||
content: String
|
||||
|
||||
"""
|
||||
The subsections of the document. If the document is returned from a search match, only matching content chunks are returned. For the full content of the original document, use the content field in the parent Guide.
|
||||
"""
|
||||
subsections: SubsectionCollection
|
||||
}
|
||||
|
||||
"""Document that matches a search query"""
|
||||
interface SearchResult {
|
||||
"""The title of the matching result"""
|
||||
title: String
|
||||
|
||||
"""The URL of the matching result"""
|
||||
href: String
|
||||
|
||||
"""The full content of the matching result"""
|
||||
content: String
|
||||
}
|
||||
|
||||
"""
|
||||
A collection of content chunks from a larger document in the Supabase docs.
|
||||
"""
|
||||
type SubsectionCollection {
|
||||
"""A list of edges containing nodes in this collection"""
|
||||
edges: [SubsectionEdge!]!
|
||||
|
||||
"""The nodes in this collection, directly accessible"""
|
||||
nodes: [Subsection!]!
|
||||
|
||||
"""The total count of items available in this collection"""
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
"""An edge in a collection of Subsections"""
|
||||
type SubsectionEdge {
|
||||
"""The Subsection at the end of the edge"""
|
||||
node: Subsection!
|
||||
}
|
||||
|
||||
"""A content chunk taken from a larger document in the Supabase docs"""
|
||||
type Subsection {
|
||||
"""The title of the subsection"""
|
||||
title: String
|
||||
|
||||
"""The URL of the subsection"""
|
||||
href: String
|
||||
|
||||
"""The content of the subsection"""
|
||||
content: String
|
||||
}
|
||||
|
||||
"""
|
||||
A reference document containing a description of a Supabase CLI command
|
||||
"""
|
||||
type CLICommandReference implements SearchResult {
|
||||
"""The title of the document"""
|
||||
title: String
|
||||
|
||||
"""The URL of the document"""
|
||||
href: String
|
||||
|
||||
"""The content of the reference document, as text"""
|
||||
content: String
|
||||
}
|
||||
|
||||
"""
|
||||
A reference document containing a description of a function from a Supabase client library
|
||||
"""
|
||||
type ClientLibraryFunctionReference implements SearchResult {
|
||||
"""The title of the document"""
|
||||
title: String
|
||||
|
||||
"""The URL of the document"""
|
||||
href: String
|
||||
|
||||
"""The content of the reference document, as text"""
|
||||
content: String
|
||||
|
||||
"""The programming language for which the function is written"""
|
||||
language: Language!
|
||||
|
||||
"""The name of the function or method"""
|
||||
methodName: String
|
||||
}
|
||||
|
||||
enum Language {
|
||||
JAVASCRIPT
|
||||
SWIFT
|
||||
DART
|
||||
CSHARP
|
||||
KOTLIN
|
||||
PYTHON
|
||||
}
|
||||
|
||||
"""A document describing how to troubleshoot an issue when using Supabase"""
|
||||
type TroubleshootingGuide implements SearchResult {
|
||||
"""The title of the troubleshooting guide"""
|
||||
title: String
|
||||
|
||||
"""The URL of the troubleshooting guide"""
|
||||
href: String
|
||||
|
||||
"""The full content of the troubleshooting guide"""
|
||||
content: String
|
||||
}
|
||||
|
||||
type RootQueryType {
|
||||
"""Get the GraphQL schema for this endpoint"""
|
||||
schema: String!
|
||||
|
||||
"""Search the Supabase docs for content matching a query string"""
|
||||
searchDocs(query: String!, limit: Int): SearchResultCollection
|
||||
}
|
||||
|
||||
"""A collection of search results containing content from Supabase docs"""
|
||||
type SearchResultCollection {
|
||||
"""A list of edges containing nodes in this collection"""
|
||||
edges: [SearchResultEdge!]!
|
||||
|
||||
"""The nodes in this collection, directly accessible"""
|
||||
nodes: [SearchResult!]!
|
||||
|
||||
"""The total count of items available in this collection"""
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
"""An edge in a collection of SearchResults"""
|
||||
type SearchResultEdge {
|
||||
"""The SearchResult at the end of the edge"""
|
||||
node: SearchResult!
|
||||
}"
|
||||
`;
|
||||
@@ -1,7 +1,19 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { POST } from './route'
|
||||
|
||||
describe('/api/graphql basic error statuses', () => {
|
||||
beforeAll(() => {
|
||||
vi.mock('server-only', () => {
|
||||
return {}
|
||||
})
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
vi.restoreAllMocks()
|
||||
vi.doUnmock('server-only')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Result } from '~/features/helpers.fn'
|
||||
import { type OpenAIClientInterface } from '~/lib/openAi'
|
||||
import { ApiError } from '../../utils'
|
||||
import { POST } from '../route'
|
||||
|
||||
const contentEmbeddingMock = vi.fn().mockImplementation(async () => Result.ok([0.1, 0.2, 0.3]))
|
||||
const openAIMock: OpenAIClientInterface = {
|
||||
createContentEmbedding: contentEmbeddingMock,
|
||||
}
|
||||
vi.mock(import('~/lib/openAi'), () => ({
|
||||
openAI: () => openAIMock,
|
||||
}))
|
||||
|
||||
const rpcSpy = vi.fn().mockImplementation((funcName, params) => {
|
||||
if (funcName === 'search_content') {
|
||||
const limit = params?.max_result || 2
|
||||
const mockResults = [
|
||||
{
|
||||
type: 'markdown',
|
||||
page_title: 'Test Guide',
|
||||
href: '/guides/test',
|
||||
content: params?.include_full_content ? 'Test content' : null,
|
||||
subsections: [
|
||||
{ title: 'Introduction', content: 'Introduction content' },
|
||||
{ title: 'Details', content: 'Details content' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'markdown',
|
||||
page_title: 'Another Guide',
|
||||
href: '/guides/another',
|
||||
content: params?.include_full_content ? 'Another content' : null,
|
||||
subsections: [{ title: 'Getting Started', content: 'Getting Started content' }],
|
||||
},
|
||||
]
|
||||
return Promise.resolve({ data: mockResults.slice(0, limit), error: null })
|
||||
}
|
||||
return Promise.resolve({ data: [], error: null })
|
||||
})
|
||||
vi.mock('~/lib/supabase', () => ({
|
||||
supabase: () => ({
|
||||
rpc: rpcSpy,
|
||||
}),
|
||||
}))
|
||||
|
||||
describe('/api/graphql searchDocs', () => {
|
||||
it('should return search results when given a valid query', async () => {
|
||||
const searchQuery = `
|
||||
query {
|
||||
searchDocs(query: "authentication") {
|
||||
nodes {
|
||||
title
|
||||
href
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const request = new Request('http://localhost/api/graphql', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query: searchQuery }),
|
||||
})
|
||||
|
||||
const response = await POST(request)
|
||||
const json = await response.json()
|
||||
|
||||
expect(json.errors).toBeUndefined()
|
||||
expect(json.data).toBeDefined()
|
||||
expect(json.data.searchDocs).toBeDefined()
|
||||
expect(json.data.searchDocs.nodes).toBeInstanceOf(Array)
|
||||
expect(json.data.searchDocs.nodes).toHaveLength(2)
|
||||
expect(json.data.searchDocs.nodes[0]).toMatchObject({
|
||||
title: 'Test Guide',
|
||||
href: '/guides/test',
|
||||
})
|
||||
})
|
||||
|
||||
it('should respect the limit parameter', async () => {
|
||||
const searchQuery = `
|
||||
query {
|
||||
searchDocs(query: "database", limit: 1) {
|
||||
nodes {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const request = new Request('http://localhost/api/graphql', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query: searchQuery }),
|
||||
})
|
||||
|
||||
const response = await POST(request)
|
||||
const json = await response.json()
|
||||
|
||||
expect(json.errors).toBeUndefined()
|
||||
expect(json.data.searchDocs.nodes).toHaveLength(1)
|
||||
expect(json.data.searchDocs.nodes[0].title).toBe('Test Guide')
|
||||
expect(rpcSpy).toHaveBeenCalledWith(
|
||||
'search_content',
|
||||
expect.objectContaining({
|
||||
max_result: 1,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('should include content field when requested', async () => {
|
||||
const searchQuery = `
|
||||
query {
|
||||
searchDocs(query: "api") {
|
||||
nodes {
|
||||
title
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const request = new Request('http://localhost/api/graphql', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query: searchQuery }),
|
||||
})
|
||||
|
||||
const response = await POST(request)
|
||||
const json = await response.json()
|
||||
|
||||
expect(json.errors).toBeUndefined()
|
||||
expect(json.data.searchDocs.nodes[0].content).toBe('Test content')
|
||||
expect(rpcSpy).toHaveBeenCalledWith(
|
||||
'search_content',
|
||||
expect.objectContaining({
|
||||
include_full_content: true,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('should handle errors from embedding creation', async () => {
|
||||
contentEmbeddingMock.mockImplementationOnce(() => {
|
||||
return Result.error(new ApiError('Embedding generation failed'))
|
||||
})
|
||||
|
||||
const searchQuery = `
|
||||
query {
|
||||
searchDocs(query: "failed query") {
|
||||
nodes {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const request = new Request('http://localhost/api/graphql', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query: searchQuery }),
|
||||
})
|
||||
|
||||
const response = await POST(request)
|
||||
const json = await response.json()
|
||||
|
||||
expect(json.errors).toBeDefined()
|
||||
expect(json.errors[0].message).toBe('Internal Server Error')
|
||||
})
|
||||
|
||||
it('should require a query parameter', async () => {
|
||||
const searchQuery = `
|
||||
query {
|
||||
searchDocs {
|
||||
nodes {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
const request = new Request('http://localhost/api/graphql', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query: searchQuery }),
|
||||
})
|
||||
|
||||
const response = await POST(request)
|
||||
const json = await response.json()
|
||||
|
||||
expect(json.errors).toBeDefined()
|
||||
expect(json.errors[0].message).toContain('required')
|
||||
})
|
||||
})
|
||||
@@ -4,7 +4,7 @@ import { createClient } from '@supabase/supabase-js'
|
||||
import { revalidateTag } from 'next/cache'
|
||||
import { headers } from 'next/headers'
|
||||
import { NextRequest } from 'next/server'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from 'vitest'
|
||||
|
||||
import { _handleRevalidateRequest } from './route'
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const response = await _handleRevalidateRequest(request)
|
||||
expect(response.status).toBe(401)
|
||||
@@ -83,7 +83,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
},
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const response = await _handleRevalidateRequest(request)
|
||||
expect(response.status).toBe(401)
|
||||
@@ -99,7 +99,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
body: JSON.stringify({ invalid: 'body' }),
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const response = await _handleRevalidateRequest(request)
|
||||
expect(response.status).toBe(400)
|
||||
@@ -115,7 +115,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
body: JSON.stringify({ tags: ['graphql', 'wrappers'] }),
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
mockSupabaseClient.rpc.mockResolvedValue({ data: [] })
|
||||
|
||||
@@ -135,7 +135,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
body: JSON.stringify({ tags: ['graphql'] }),
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const fiveHoursAgo = new Date(mockDate.getTime() - 5 * 60 * 60 * 1000)
|
||||
mockSupabaseClient.rpc.mockResolvedValue({
|
||||
@@ -156,7 +156,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
body: JSON.stringify({ tags: ['graphql'] }),
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const sevenHoursAgo = new Date(mockDate.getTime() - 7 * 60 * 60 * 1000)
|
||||
mockSupabaseClient.rpc.mockResolvedValue({
|
||||
@@ -177,7 +177,7 @@ describe('_handleRevalidateRequest', () => {
|
||||
body: JSON.stringify({ tags: ['graphql'] }),
|
||||
})
|
||||
|
||||
vi.mocked(headers).mockReturnValue(new Headers(request.headers))
|
||||
vi.mocked(headers).mockReturnValue(Promise.resolve(new Headers(request.headers)))
|
||||
|
||||
const oneHourAgo = new Date(mockDate.getTime() - 1 * 60 * 60 * 1000)
|
||||
mockSupabaseClient.rpc.mockResolvedValue({
|
||||
|
||||
@@ -19,7 +19,7 @@ const requestBodySchema = z.object({
|
||||
export const POST = handleError(_handleRevalidateRequest)
|
||||
|
||||
export async function _handleRevalidateRequest(request: NextRequest) {
|
||||
const requestHeaders = headers()
|
||||
const requestHeaders = await headers()
|
||||
const authorization = requestHeaders.get('Authorization')
|
||||
if (!authorization) {
|
||||
return new Response('Missing Authorization header', { status: 401 })
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { z, type ZodError } from 'zod'
|
||||
import { type PostgrestError } from '@supabase/supabase-js'
|
||||
import { type ZodError } from 'zod'
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(message: string) {
|
||||
type ObjectOrNever = object | never
|
||||
|
||||
export type ApiErrorGeneric = ApiError<ObjectOrNever>
|
||||
|
||||
export class ApiError<Details extends ObjectOrNever = never> extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public source?: unknown,
|
||||
public details?: Details
|
||||
) {
|
||||
super(message)
|
||||
}
|
||||
|
||||
@@ -14,9 +23,9 @@ export class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidRequestError extends ApiError {
|
||||
constructor(message: string, source?: unknown) {
|
||||
super(`Invalid request: ${message}`)
|
||||
export class InvalidRequestError<Details extends ObjectOrNever = never> extends ApiError<Details> {
|
||||
constructor(message: string, source?: unknown, details?: Details) {
|
||||
super(`Invalid request: ${message}`, source, details)
|
||||
}
|
||||
|
||||
isPrivate() {
|
||||
@@ -28,6 +37,15 @@ export class InvalidRequestError extends ApiError {
|
||||
}
|
||||
}
|
||||
|
||||
export function convertUnknownToApiError(error: unknown): ApiError {
|
||||
return new ApiError('Unknown error', error)
|
||||
}
|
||||
|
||||
export function convertPostgrestToApiError(error: PostgrestError): ApiError {
|
||||
const message = `${error.code}: ${error.hint}`
|
||||
return new ApiError(message, error)
|
||||
}
|
||||
|
||||
export function convertZodToInvalidRequestError(
|
||||
error: ZodError,
|
||||
prelude?: string
|
||||
|
||||
@@ -9,7 +9,7 @@ const LazyGraphiQL = dynamic(
|
||||
async () => {
|
||||
const { GraphiQL: GraphiQLPrimitive } = await import('graphiql')
|
||||
const { createGraphiQLFetcher } = await import('@graphiql/toolkit')
|
||||
await import('graphiql/graphiql.css')
|
||||
await import('graphiql/style.css')
|
||||
|
||||
return function GraphiQL(props: Omit<ComponentProps<typeof GraphiQLPrimitive>, 'fetcher'>) {
|
||||
const fetcher = createGraphiQLFetcher({
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const AiGuidePage = async ({ params }: { params: Params }) => {
|
||||
const AiGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['ai', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ interface Params {
|
||||
slug: string
|
||||
}
|
||||
|
||||
const PythonClientDocs = async ({ params }: { params: Params }) => {
|
||||
const PythonClientDocs = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const { meta, ...data } = await getContent(params)
|
||||
|
||||
const options = {
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const ApiGuidePage = async ({ params }: { params: Params }) => {
|
||||
const ApiGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['api', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const AuthGuidePage = async ({ params }: { params: Params }) => {
|
||||
const AuthGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['auth', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const CronGuidePage = async ({ params }: { params: Params }) => {
|
||||
const CronGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['cron', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const DatabaseGuidePage = async ({ params }: { params: Params }) => {
|
||||
const DatabaseGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['database', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -208,7 +208,8 @@ interface Params {
|
||||
slug?: string[]
|
||||
}
|
||||
|
||||
const WrappersDocs = async ({ params }: { params: Params }) => {
|
||||
const WrappersDocs = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const { isExternal, meta, ...data } = await getContent(params)
|
||||
|
||||
const options = isExternal
|
||||
@@ -271,6 +272,7 @@ const getContent = async (params: Params) => {
|
||||
editLink = `${org}/${repo}/blob/${tag}/${docsDir}/${remoteFile}`
|
||||
|
||||
const response = await fetch(`https://raw.githubusercontent.com/${repoPath}`, {
|
||||
cache: 'force-cache',
|
||||
next: { tags: [REVALIDATION_TAGS.WRAPPERS] },
|
||||
})
|
||||
const rawContent = await response.text()
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const DeploymentGuidePage = async ({ params }: { params: Params }) => {
|
||||
const DeploymentGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['deployment', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ const pageMap = [
|
||||
|
||||
type Params = { slug: string }
|
||||
|
||||
const ActionDocs = async ({ params }: { params: Params }) => {
|
||||
const ActionDocs = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const { meta, ...data } = await getContent(params)
|
||||
|
||||
const options = {
|
||||
|
||||
@@ -42,7 +42,8 @@ interface Params {
|
||||
slug?: string[]
|
||||
}
|
||||
|
||||
const TerraformDocs = async ({ params }: { params: Params }) => {
|
||||
const TerraformDocs = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const { meta, ...data } = await getContent(params)
|
||||
|
||||
const options = {
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const FunctionsGuidePage = async ({ params }: { params: Params }) => {
|
||||
const FunctionsGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['functions', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const GettingStartedGuidePage = async ({ params }: { params: Params }) => {
|
||||
const GettingStartedGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['getting-started', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ async function getAiPromptImpl(prompt: string) {
|
||||
}
|
||||
export const getAiPrompt = cache(getAiPromptImpl)
|
||||
|
||||
export async function generateAiPromptMetadata({ params: { slug } }: { params: { slug: string } }) {
|
||||
export async function generateAiPromptMetadata(props: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = await props.params
|
||||
const prompt = await getAiPrompt(slug)
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
|
||||
export const dynamicParams = false
|
||||
|
||||
export default async function AiPromptsPage({ params: { slug } }: { params: { slug: string } }) {
|
||||
export default async function AiPromptsPage(props: { params: Promise<{ slug: string }> }) {
|
||||
const params = await props.params
|
||||
|
||||
const { slug } = params
|
||||
|
||||
let { heading, content } = await getAiPrompt(slug)
|
||||
content = `
|
||||
## How to use
|
||||
|
||||
@@ -108,7 +108,8 @@ interface Params {
|
||||
slug?: string[]
|
||||
}
|
||||
|
||||
const PGGraphQLDocs = async ({ params }: { params: Params }) => {
|
||||
const PGGraphQLDocs = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const { meta, ...data } = await getContent(params)
|
||||
|
||||
const options = {
|
||||
@@ -137,7 +138,7 @@ const getContent = async ({ slug }: Params) => {
|
||||
|
||||
const response = await fetch(
|
||||
`https://raw.githubusercontent.com/${org}/${repo}/${branch}/${docsDir}/${remoteFile}`,
|
||||
{ next: { tags: [REVALIDATION_TAGS.GRAPHQL] } }
|
||||
{ cache: 'force-cache', next: { tags: [REVALIDATION_TAGS.GRAPHQL] } }
|
||||
)
|
||||
|
||||
const content = await response.text()
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const IntegrationsGuidePage = async ({ params }: { params: Params }) => {
|
||||
const IntegrationsGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['integrations', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IS_PLATFORM } from 'common'
|
||||
import { unstable_cache } from 'next/cache'
|
||||
|
||||
import { type NavMenuSection } from '~/components/Navigation/Navigation.types'
|
||||
import { REVALIDATION_TAGS } from '~/features/helpers.fetch'
|
||||
import Layout from '~/layouts/guides'
|
||||
import { supabaseMisc } from '~/lib/supabaseMisc'
|
||||
|
||||
@@ -13,7 +13,9 @@ export default async function IntegrationsLayout({ children }: { children: React
|
||||
|
||||
// Will need to turn on revalidation later, just turning it off for now so we
|
||||
// can slowly turn things back on while monitoring usage
|
||||
const getPartners = unstable_cache(getPartnersImpl, [], { revalidate: false })
|
||||
const getPartners = unstable_cache(getPartnersImpl, [], {
|
||||
tags: [REVALIDATION_TAGS.PARTNERS],
|
||||
})
|
||||
async function getPartnersImpl() {
|
||||
if (!IS_PLATFORM) return []
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const LocalDevelopmentGuidePage = async ({ params }: { params: Params }) => {
|
||||
const LocalDevelopmentGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['local-development', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const PlatformGuidePage = async ({ params }: { params: Params }) => {
|
||||
const PlatformGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['platform', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const QueuesGuidePage = async ({ params }: { params: Params }) => {
|
||||
const QueuesGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['queues', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const RealtimeGuidePage = async ({ params }: { params: Params }) => {
|
||||
const RealtimeGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['realtime', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const ResourcesGuidePage = async ({ params }: { params: Params }) => {
|
||||
const ResourcesGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['resources', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const SecurityGuidePage = async ({ params }: { params: Params }) => {
|
||||
const SecurityGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['security', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const SelfHostingGuidePage = async ({ params }: { params: Params }) => {
|
||||
const SelfHostingGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['self-hosting', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const StorageGuidePage = async ({ params }: { params: Params }) => {
|
||||
const StorageGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['storage', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ export const dynamicParams = false
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
const MonitoringTroubleshootingGuidePage = async ({ params }: { params: Params }) => {
|
||||
const MonitoringTroubleshootingGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
const params = await props.params
|
||||
const slug = ['telemetry', ...(params.slug ?? [])]
|
||||
const data = await getGuidesMarkdown(slug)
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ import { PROD_URL } from '~/lib/constants'
|
||||
// export const revalidate = 86_400
|
||||
export const dynamicParams = false
|
||||
|
||||
export default async function TroubleshootingEntryPage({
|
||||
params: { slug },
|
||||
}: {
|
||||
params: { slug: string }
|
||||
export default async function TroubleshootingEntryPage(props: {
|
||||
params: Promise<{ slug: string }>
|
||||
}) {
|
||||
const params = await props.params
|
||||
|
||||
const { slug } = params
|
||||
|
||||
const allTroubleshootingEntries = await getAllTroubleshootingEntries()
|
||||
const entry = allTroubleshootingEntries.find((entry) => getArticleSlug(entry) === slug)
|
||||
|
||||
@@ -23,7 +25,11 @@ export default async function TroubleshootingEntryPage({
|
||||
return <TroubleshootingPage entry={entry} />
|
||||
}
|
||||
|
||||
export const generateMetadata = async ({ params: { slug } }: { params: { slug: string } }) => {
|
||||
export const generateMetadata = async (props: { params: Promise<{ slug: string }> }) => {
|
||||
const params = await props.params
|
||||
|
||||
const { slug } = params
|
||||
|
||||
const allTroubleshootingEntries = await getAllTroubleshootingEntries()
|
||||
const entry = allTroubleshootingEntries.find((entry) => getArticleSlug(entry) === slug)
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ import {
|
||||
|
||||
export const dynamicParams = false
|
||||
|
||||
export default async function ReferencePage({
|
||||
params: { slug },
|
||||
}: {
|
||||
params: { slug: Array<string> }
|
||||
}) {
|
||||
export default async function ReferencePage(props: { params: Promise<{ slug: Array<string> }> }) {
|
||||
const params = await props.params
|
||||
|
||||
const { slug } = params
|
||||
|
||||
if (!Object.keys(REFERENCES).includes(slug[0].replaceAll('-', '_'))) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli'
|
||||
|
||||
const config: CodegenConfig = {
|
||||
overwrite: true,
|
||||
schema: './__generated__/schema.graphql',
|
||||
generates: {
|
||||
'__generated__/graphql.ts': {
|
||||
plugins: ['typescript', 'typescript-resolvers'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -30,6 +30,8 @@ const getLinearTeam = (pathname: string) => {
|
||||
return 'Dev Workflows'
|
||||
case 'integrations':
|
||||
return 'API'
|
||||
case 'security':
|
||||
return 'Security'
|
||||
case 'platform':
|
||||
case 'monitoring-troubleshooting':
|
||||
return 'Infra'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { KJUR } from 'jsrsasign'
|
||||
import { useState, ChangeEvent } from 'react'
|
||||
import { ChangeEvent, useState } from 'react'
|
||||
import { Button, CodeBlock, Input, Select } from 'ui'
|
||||
|
||||
const JWT_HEADER = { alg: 'HS256', typ: 'JWT' }
|
||||
@@ -53,7 +53,7 @@ const generateRandomString = (length: number) => {
|
||||
return result
|
||||
}
|
||||
|
||||
export default function JwtGenerator({}) {
|
||||
export default function JwtGenerator() {
|
||||
const secret = generateRandomString(40)
|
||||
|
||||
const [jwtSecret, setJwtSecret] = useState(secret)
|
||||
@@ -110,6 +110,7 @@ export default function JwtGenerator({}) {
|
||||
<div className="grid mb-8">
|
||||
<label htmlFor="token">The JWT will be generated from this info:</label>
|
||||
<Input.TextArea
|
||||
key={JSON.stringify(token)}
|
||||
id="token"
|
||||
type="text"
|
||||
rows={6}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { Command, Search, Menu } from 'lucide-react'
|
||||
import { memo, useState } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import type { FC } from 'react'
|
||||
import { memo, useState } from 'react'
|
||||
import { Command, Search, Menu } from 'lucide-react'
|
||||
|
||||
import { useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { useIsLoggedIn, useIsUserLoading, useUser } from 'common'
|
||||
import { Button, buttonVariants, cn } from 'ui'
|
||||
import { CommandMenuTrigger } from 'ui-patterns/CommandMenu'
|
||||
|
||||
import { AuthenticatedDropdownMenu, CommandMenuTrigger } from 'ui-patterns'
|
||||
import GlobalNavigationMenu from './GlobalNavigationMenu'
|
||||
import useDropdownMenu from './useDropdownMenu'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
const GlobalMobileMenu = dynamic(() => import('./GlobalMobileMenu'))
|
||||
const TopNavDropdown = dynamic(() => import('./TopNavDropdown'))
|
||||
|
||||
@@ -17,6 +19,8 @@ const TopNavBar: FC = () => {
|
||||
const isLoggedIn = useIsLoggedIn()
|
||||
const isUserLoading = useIsUserLoading()
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const user = useUser()
|
||||
const menu = useDropdownMenu(user)
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -95,7 +99,11 @@ const TopNavBar: FC = () => {
|
||||
<Link href="/dev-secret-auth">Dev-only secret sign-in</Link>
|
||||
</Button>
|
||||
)}
|
||||
<TopNavDropdown />
|
||||
{isLoggedIn ? (
|
||||
<AuthenticatedDropdownMenu menu={menu} user={user} site="docs" />
|
||||
) : (
|
||||
<TopNavDropdown />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
cn,
|
||||
themes,
|
||||
} from 'ui'
|
||||
|
||||
import MenuIconPicker from './MenuIconPicker'
|
||||
|
||||
const menu = [
|
||||
@@ -70,7 +69,7 @@ const TopNavDropdown = () => {
|
||||
<Menu size={18} strokeWidth={1} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-64">
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-52">
|
||||
{menu.map((menuSection, sectionIdx) => (
|
||||
<Fragment key={`topnav--${sectionIdx}`}>
|
||||
{sectionIdx !== 0 && <DropdownMenuSeparator key={`topnav--${sectionIdx}`} />}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
'use client'
|
||||
|
||||
import type { User } from '@supabase/supabase-js'
|
||||
import { LogOut, Globe, LifeBuoy, Settings, UserIcon, Database } from 'lucide-react'
|
||||
import { logOut } from 'common'
|
||||
|
||||
import type { menuItem } from 'ui-patterns/AuthenticatedDropdownMenu'
|
||||
import { IconGitHub } from './MenuIcons'
|
||||
|
||||
const useDropdownMenu = (user: User | null) => {
|
||||
const menu: menuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: user?.email ?? "You're logged in",
|
||||
type: 'text',
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
label: 'Account Preferences',
|
||||
icon: Settings,
|
||||
href: 'https://supabase.com/dashboard/account/me',
|
||||
},
|
||||
{
|
||||
label: 'All Projects',
|
||||
icon: Database,
|
||||
href: 'https://supabase.com/dashboard/projects',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Supabase.com',
|
||||
icon: Globe,
|
||||
href: 'https://supabase.com',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'GitHub',
|
||||
icon: IconGitHub as any,
|
||||
href: 'https://github.com/supabase/supabase',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Support',
|
||||
icon: LifeBuoy,
|
||||
href: 'https://supabase.com/support',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Theme',
|
||||
type: 'theme',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Logout',
|
||||
type: 'button',
|
||||
icon: LogOut,
|
||||
onClick: async () => {
|
||||
await logOut()
|
||||
window.location.reload()
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
export default useDropdownMenu
|
||||
@@ -0,0 +1,7 @@
|
||||
interface PriceProps {
|
||||
price: string
|
||||
}
|
||||
|
||||
export const Price: React.FC<PriceProps> = ({ price }) => {
|
||||
return <span translate="no">${price}</span>
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import CopyToClipboard from 'react-copy-to-clipboard'
|
||||
import { withErrorBoundary } from 'react-error-boundary'
|
||||
import { proxy, useSnapshot } from 'valtio'
|
||||
|
||||
import { useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { Button_Shadcn_ as Button, Input_Shadcn_ as Input, cn } from 'ui'
|
||||
|
||||
import {
|
||||
@@ -36,7 +36,7 @@ import { useOrganizationsQuery } from '~/lib/fetch/organizations'
|
||||
import { type SupavisorConfigData, useSupavisorConfigQuery } from '~/lib/fetch/pooler'
|
||||
import { useProjectApiQuery } from '~/lib/fetch/projectApi'
|
||||
import { isProjectPaused, type ProjectsData, useProjectsQuery } from '~/lib/fetch/projects'
|
||||
import { LOCAL_STORAGE_KEYS, retrieve, storeOrRemoveNull } from '~/lib/storage'
|
||||
import { retrieve, storeOrRemoveNull } from '~/lib/storage'
|
||||
import { useOnLogout } from '~/lib/userAuth'
|
||||
|
||||
type ProjectOrgDataState =
|
||||
|
||||
@@ -1 +1 @@
|
||||
There is no fixed fee for a Preview branch. You only pay for the usage it incurs. With Compute costs of $0.01344 per hour, a branch running on Micro Compute size starts at $0.32 per day.
|
||||
There is no fixed fee for a Preview branch. You only pay for the usage it incurs. With Compute costs of <Price price="0.01344" /> per hour, a branch running on Micro Compute size starts at <Price price="0.32" /> per day.
|
||||
@@ -1,8 +1,9 @@
|
||||
$2 per 1 million invocations. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="2" /> per 1 million invocations. You are only charged for usage exceeding your subscription
|
||||
plan's quota.
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | --------- | ---------------------------- |
|
||||
| Free | 500,000 | - |
|
||||
| Pro | 2 million | $2 per 1 million invocations |
|
||||
| Team | 2 million | $2 per 1 million invocations |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | --------- | --------------------------------------------- |
|
||||
| Free | 500,000 | - |
|
||||
| Pro | 2 million | <Price price="2" /> per 1 million invocations |
|
||||
| Team | 2 million | <Price price="2" /> per 1 million invocations |
|
||||
| Enterprise | Custom | Custom |
|
||||
@@ -1 +1,2 @@
|
||||
$0.00325 per MAU. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="0.00325" /> per MAU. You are only charged for usage exceeding your subscription plan's
|
||||
quota.
|
||||
@@ -1 +1,2 @@
|
||||
$0.015 per SSO MAU. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="0.015" /> per SSO MAU. You are only charged for usage exceeding your subscription plan's
|
||||
quota.
|
||||
@@ -1 +1,2 @@
|
||||
$0.00325 per Third-Party MAU. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="0.00325" /> per Third-Party MAU. You are only charged for usage exceeding your subscription
|
||||
plan's quota.
|
||||
@@ -1,7 +1,8 @@
|
||||
$0.1027 per hour ($75 per month) for the first project. $0.0137 per hour ($10 per month) for every additional project.
|
||||
<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.
|
||||
|
||||
| Plan | Project 1 per month | Project 2 per month | Project 3 per month |
|
||||
| ---------- | ------------------- | ------------------- | ------------------- |
|
||||
| Pro | $75 | $10 | $10 |
|
||||
| Team | $75 | $10 | $10 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Project 1 per month | Project 2 per month | Project 3 per month |
|
||||
| ---------- | -------------------- | -------------------- | -------------------- |
|
||||
| Pro | <Price price="75" /> | <Price price="10" /> | <Price price="10" /> |
|
||||
| Team | <Price price="75" /> | <Price price="10" /> | <Price price="10" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
@@ -1,7 +1,7 @@
|
||||
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 |
|
||||
| --------------------------------- | ---------------- | ----------------- |
|
||||
| 7 | $0.137 | $100 |
|
||||
| 14 | $0.274 | $200 |
|
||||
| 28 | $0.55 | $400 |
|
||||
| Recovery Retention Period in Days | Hourly Price USD | Monthly Price USD |
|
||||
| --------------------------------- | ----------------------- | --------------------- |
|
||||
| 7 | <Price price="0.137" /> | <Price price="100" /> |
|
||||
| 14 | <Price price="0.274" /> | <Price price="200" /> |
|
||||
| 28 | <Price price="0.55" /> | <Price price="400" /> |
|
||||
@@ -1,8 +1,9 @@
|
||||
$10 per 1,000 peak connections. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="10" /> per 1,000 peak connections. You are only charged for usage exceeding your subscription
|
||||
plan's quota.
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | ------------------------------ |
|
||||
| Free | 200 | - |
|
||||
| Pro | 500 | $10 per 1,000 peak connections |
|
||||
| Team | 500 | $10 per 1,000 peak connections |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | ----------------------------------------------- |
|
||||
| Free | 200 | - |
|
||||
| Pro | 500 | <Price price="10" /> per 1,000 peak connections |
|
||||
| Team | 500 | <Price price="10" /> per 1,000 peak connections |
|
||||
| Enterprise | Custom | Custom |
|
||||
@@ -1,8 +1,9 @@
|
||||
$2.50 per 1 million messages. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="2.50" /> per 1 million messages. You are only charged for usage exceeding your subscription
|
||||
plan's quota.
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | --------- | ---------------------------- |
|
||||
| Free | 2 million | - |
|
||||
| Pro | 5 million | $2.50 per 1 million messages |
|
||||
| Team | 5 million | $2.50 per 1 million messages |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | --------- | --------------------------------------------- |
|
||||
| Free | 2 million | - |
|
||||
| Pro | 5 million | <Price price="2.50" /> per 1 million messages |
|
||||
| Team | 5 million | <Price price="2.50" /> per 1 million messages |
|
||||
| Enterprise | Custom | Custom |
|
||||
+7
-6
@@ -1,4 +1,5 @@
|
||||
$5 per 1,000 origin images. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="5" /> per 1,000 origin images. You are only charged for usage exceeding your subscription
|
||||
plan's quota.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
@@ -6,8 +7,8 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
</Admonition>
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | -------------------------- |
|
||||
| Pro | 100 | $5 per 1,000 origin images |
|
||||
| Team | 100 | $5 per 1,000 origin images |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | ------------------------------------------- |
|
||||
| Pro | 100 | <Price price="5" /> per 1,000 origin images |
|
||||
| Team | 100 | <Price price="5" /> per 1,000 origin images |
|
||||
| Enterprise | Custom | Custom |
|
||||
@@ -1,8 +1,9 @@
|
||||
$0.00002919 per GB-Hr ($0.021 per GB per month). You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="0.00002919" /> per GB-Hr (<Price price="0.021" /> per GB per month). You are only
|
||||
charged for usage exceeding your subscription plan's quota.
|
||||
|
||||
| Plan | Quota in GB | Over-Usage per GB | Quota in GB-Hrs | Over-Usage per GB-Hr |
|
||||
| ---------- | ----------- | ----------------- | --------------- | -------------------- |
|
||||
| Free | 1 | - | 744 | - |
|
||||
| Pro | 100 | $0.021 | 74,400 | $0.00002919 |
|
||||
| Team | 100 | $0.021 | 74,400 | $0.00002919 |
|
||||
| Enterprise | Custom | Custom | Custom | Custom |
|
||||
| Plan | Quota in GB | Over-Usage per GB | Quota in GB-Hrs | Over-Usage per GB-Hr |
|
||||
| ---------- | ----------- | ----------------------- | --------------- | ---------------------------- |
|
||||
| Free | 1 | - | 744 | - |
|
||||
| Pro | 100 | <Price price="0.021" /> | 74,400 | <Price price="0.00002919" /> |
|
||||
| Team | 100 | <Price price="0.021" /> | 74,400 | <Price price="0.00002919" /> |
|
||||
| Enterprise | Custom | Custom | Custom | Custom |
|
||||
@@ -9,6 +9,8 @@ sitemapPriority: 0.5
|
||||
|
||||
As of 7th Feb 2024, [this repository](https://github.com/supabase-community/auth-ui) is no longer maintained by the Supabase Team. At the moment, the team does not have capacity to give the expected level of care to this repository. We may revisit Auth UI in the future but regrettably have to leave it on hold for now as we focus on other priorities such as improving the Server-Side Rendering (SSR) package and advanced Auth primitives.
|
||||
|
||||
As an alternative you can use the [Supabase UI Library](https://supabase.com/ui) which has auth ready blocks to use in your projects.
|
||||
|
||||
</Admonition>
|
||||
|
||||
Auth UI is a pre-built React component for authenticating users.
|
||||
|
||||
@@ -643,7 +643,7 @@ const templates = {
|
||||
|
||||
function generateConfirmationURL(email_data) {
|
||||
// TODO: replace the ref with your project ref
|
||||
return `https://<ref>.supabase.co/auth/v1/verify?token=${email_data.token}&type=${email_data.email_action_type}&redirect_to=${email_data.redirect_to}`
|
||||
return `https://<ref>.supabase.co/auth/v1/verify?token=${email_data.token_hash}&type=${email_data.email_action_type}&redirect_to=${email_data.redirect_to}`
|
||||
}
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
@@ -755,7 +755,7 @@ const templates = {
|
||||
|
||||
function generateConfirmationURL(email_data) {
|
||||
// TODO: replace the ref with your project ref
|
||||
return `https://<ref>.supabase.co/auth/v1/verify?token=${email_data.token}&type=${email_data.email_action_type}&redirect_to=${email_data.redirect_to}`
|
||||
return `https://<ref>.supabase.co/auth/v1/verify?token=${email_data.token_hash}&type=${email_data.email_action_type}&redirect_to=${email_data.redirect_to}`
|
||||
}
|
||||
|
||||
async function sendEmailWithPostmark(user: any, email_data: any, serverToken: string): Promise<Response> {
|
||||
|
||||
@@ -565,7 +565,7 @@ Fill in your `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`:
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```txt .env.local
|
||||
```txt name=.env.local
|
||||
NEXT_PUBLIC_SUPABASE_URL=<your_supabase_project_url>
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
|
||||
```
|
||||
|
||||
@@ -368,7 +368,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
|
||||
) {
|
||||
install(GoTrue)
|
||||
install(ComposeAuth) {
|
||||
nativeAppleLogin()
|
||||
appleNativeLogin()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -694,7 +694,7 @@ val supabaseClient = createSupabaseClient(
|
||||
supabaseUrl = "SUPABASE_URL",
|
||||
supabaseKey = "SUPABASE_KEY"
|
||||
) {
|
||||
install(GoTrue)
|
||||
install(Auth)
|
||||
install(ComposeAuth) {
|
||||
nativeGoogleLogin("WEB_GOOGLE_CLIENT_ID") //Use the Web Client ID, not the Android one!
|
||||
}
|
||||
|
||||
+16
-31
@@ -37,15 +37,11 @@ If you are not able to use [Clerk's Connect with Supabase page](https://dashboar
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```typescript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient('https://<supabase-project>.supabase.co', 'SUPABASE_ANON_KEY', {
|
||||
accessToken: () => {
|
||||
return Clerk.session?.getToken()
|
||||
},
|
||||
})
|
||||
```
|
||||
<$CodeSample
|
||||
path="/clerk/hooks/useSupabaseClient.ts"
|
||||
lines={[[6, 14]]}
|
||||
hideElidedLines={true}
|
||||
/>
|
||||
|
||||
</TabPanel>
|
||||
|
||||
@@ -99,34 +95,23 @@ The recommended way to design RLS policies with Clerk is to use claims present i
|
||||
|
||||
### Example: Check user organization role
|
||||
|
||||
```sql
|
||||
create policy "Only organization admins can insert in table"
|
||||
on table_name
|
||||
for insert
|
||||
to authenticated
|
||||
with check (
|
||||
((select auth.jwt()->>'org_role') = 'org:admin')
|
||||
and
|
||||
(organization_id = (select auth.jwt()->>'org_id'))
|
||||
);
|
||||
```
|
||||
<$CodeSample
|
||||
path="/clerk/supabase/migrations/20250501155648_setup_database.sql"
|
||||
lines={[[10, 18]]}
|
||||
hideElidedLines={true}
|
||||
/>
|
||||
|
||||
This RLS policy checks that the newly inserted row in the table has the user's declared organization ID (from the `org_id` session token claim) in the `organization_id` column. Additionally it ensures that they're an `org:admin`.
|
||||
This RLS policy checks that the newly inserted row in the table has the user's declared organization ID in the `organization_id` column. Additionally it ensures that they're an `org:admin`.
|
||||
|
||||
This way only organization admins can add rows to the table, for organizations they're a member of.
|
||||
|
||||
### Example: Check user has passed second factor verification
|
||||
|
||||
```sql
|
||||
create policy "Only users that have passed second factor verification can read from table"
|
||||
on table_name
|
||||
for select
|
||||
as restrictive
|
||||
to authenticated
|
||||
using (
|
||||
((select auth.jwt()->'fva'->>1) != '-1')
|
||||
);
|
||||
```
|
||||
<$CodeSample
|
||||
path="/clerk/supabase/migrations/20250501155648_setup_database.sql"
|
||||
lines={[[28, 35]]}
|
||||
hideElidedLines={true}
|
||||
/>
|
||||
|
||||
This example uses a restrictive RLS policy checks that the [second factor verification](https://clerk.com/docs/guides/reverification) age element in the `fva` claim is not `'-1'` indicating the user has passed through second factor verification.
|
||||
|
||||
|
||||
@@ -5,7 +5,15 @@ subtitle: 'Schedule Recurring Jobs with Cron Syntax in Postgres'
|
||||
|
||||
Supabase Cron is a Postgres Module that simplifies scheduling recurring Jobs with cron syntax and monitoring Job runs inside Postgres.
|
||||
|
||||
Cron Jobs can be created via SQL or the Cron interface inside of Supabase Dashboard and can run anywhere from every second to once a year depending on your use case.
|
||||
Cron Jobs can be created via SQL or the [Integrations -> Cron](https://supabase.com/dashboard/project/_/integrations) interface inside the Dashboard, and can run anywhere from every second to once a year depending on your use case.
|
||||
|
||||
<Image
|
||||
alt="Manage cron jobs via the Dashboard"
|
||||
src={{
|
||||
dark: '/docs/img/guides/cron/cron.jpg',
|
||||
light: '/docs/img/guides/cron/cron--light.jpg',
|
||||
}}
|
||||
/>
|
||||
|
||||
Every Job can run SQL snippets or database functions with zero network latency or make an HTTP request, such as invoking a Supabase Edge Function, with ease.
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Supabase projects come with [TimescaleDB Apache 2 Edition](https://docs.timescal
|
||||
{/* prettier-ignore */}
|
||||
```sql
|
||||
-- Enable the "timescaledb" extension
|
||||
create extension timescaledb;
|
||||
create extension timescaledb with schema extensions;
|
||||
|
||||
-- Disable the "timescaledb" extension
|
||||
drop extension if exists timescaledb;
|
||||
@@ -44,6 +44,10 @@ drop extension if exists timescaledb;
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension". To disable an extension you can call `drop extension`.
|
||||
|
||||
It's good practice to create the extension within a separate schema (like `extensions`) to keep your `public` schema clean.
|
||||
|
||||
## Usage
|
||||
|
||||
To demonstrate how `timescaledb` works, let's consider a simple example where we have a table that stores temperature data from different sensors. We will create a table named "temperatures" and store data for two sensors.
|
||||
|
||||
@@ -624,7 +624,7 @@ You can make a similar setup with a distinct project for each environment. Or ju
|
||||
|
||||
Branching is available on the Pro Plan and above. The price is:
|
||||
|
||||
- Each Preview branch costs $0.32 per day
|
||||
- Each Preview branch costs <Price price="0.32" /> per day
|
||||
- Each Preview branch is billed until it is removed
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -236,7 +236,6 @@ To prevent that, you can update the `supabase/config.toml` with the following se
|
||||
```toml
|
||||
[edge_runtime]
|
||||
policy = "per_worker"
|
||||
```
|
||||
````
|
||||
|
||||
When running with `per_worker` policy, Function won't auto-reload on edits. You will need to manually restart it by running `supabase functions serve`.
|
||||
````
|
||||
@@ -50,15 +50,46 @@ hideToc: true
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Declare Supabase Environment Variables">
|
||||
|
||||
In `app.vue`, create a Supabase client using your project URL and public API (anon) key:
|
||||
Create a `.env` file and populate with your Supabase connection variables:
|
||||
|
||||
<ProjectConfigVariables variable="url" />
|
||||
<ProjectConfigVariables variable="anonKey" />
|
||||
|
||||
Replace the existing content in your `app.vue` file with the following code.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```text name=.env.local
|
||||
SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
|
||||
SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
|
||||
```
|
||||
|
||||
```ts name=nuxt.config.tsx
|
||||
export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
supabaseUrl: process.env.SUPABASE_URL,
|
||||
supabaseAnonKey: process.env.SUPABASE_ANON_KEY,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
|
||||
In `app.vue`, create a Supabase client using your config values and replace the existing content with the following code.
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
@@ -67,7 +98,8 @@ hideToc: true
|
||||
```vue name=app.vue
|
||||
<script setup>
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>')
|
||||
const config = useRuntimeConfig()
|
||||
const supabase = createClient(config.public.supabaseUrl, config.public.supabaseAnonKey)
|
||||
const instruments = ref([])
|
||||
|
||||
async function getInstruments() {
|
||||
@@ -91,7 +123,7 @@ hideToc: true
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<StepHikeCompact.Step step={6}>
|
||||
<StepHikeCompact.Details title="Start the app">
|
||||
|
||||
Start the app, navigate to http://localhost:3000 in the browser, open the browser console, and you should see the list of instruments.
|
||||
|
||||
@@ -51,14 +51,34 @@ hideToc: true
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
<StepHikeCompact.Details title="Declare Supabase Environment Variables">
|
||||
|
||||
In `App.jsx`, create a Supabase client using your project URL and public API (anon) key:
|
||||
Create a `.env.local` file and populate with your Supabase connection variables:
|
||||
|
||||
<ProjectConfigVariables variable="url" />
|
||||
<ProjectConfigVariables variable="anonKey" />
|
||||
|
||||
Add a `getInstruments` function to fetch the data and display the query result to the page.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```text name=.env.local
|
||||
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
|
||||
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<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.
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
<StepHikeCompact.Code>
|
||||
@@ -67,7 +87,7 @@ hideToc: true
|
||||
import { useEffect, useState } from "react";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabase = createClient("https://<project>.supabase.co", "<your-anon-key>");
|
||||
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY);
|
||||
|
||||
function App() {
|
||||
const [instruments, setInstruments] = useState([]);
|
||||
@@ -97,7 +117,7 @@ hideToc: true
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<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.
|
||||
|
||||
@@ -51,13 +51,35 @@ hideToc: true
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
<StepHikeCompact.Details title="Declare Supabase Environment Variables">
|
||||
|
||||
In `App.jsx`, create a Supabase client using your project URL and public API (anon) key:
|
||||
Create a `.env.local` file and populate with your Supabase connection variables:
|
||||
|
||||
<ProjectConfigVariables variable="url" />
|
||||
<ProjectConfigVariables variable="anonKey" />
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```text name=.env.local
|
||||
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
|
||||
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
|
||||
In `App.jsx`, create a Supabase client to fetch the instruments data.
|
||||
|
||||
Add a `getInstruments` function to fetch the data and display the query result to the page.
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
@@ -65,34 +87,34 @@ hideToc: true
|
||||
|
||||
|
||||
```jsx name=src/App.jsx
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { createResource, For } from "solid-js";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { createResource, For } from "solid-js";
|
||||
|
||||
const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>');
|
||||
const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>');
|
||||
|
||||
async function getInstruments() {
|
||||
const { data } = await supabase.from("instruments").select();
|
||||
return data;
|
||||
}
|
||||
async function getInstruments() {
|
||||
const { data } = await supabase.from("instruments").select();
|
||||
return data;
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [instruments] = createResource(getInstruments);
|
||||
function App() {
|
||||
const [instruments] = createResource(getInstruments);
|
||||
|
||||
return (
|
||||
<ul>
|
||||
<For each={instruments()}>{(instrument) => <li>{instrument.name}</li>}</For>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ul>
|
||||
<For each={instruments()}>{(instrument) => <li>{instrument.name}</li>}</For>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<StepHikeCompact.Step step={6}>
|
||||
<StepHikeCompact.Details title="Start the app">
|
||||
|
||||
Start the app and go to http://localhost:3000 in a browser and you should see the list of instruments.
|
||||
|
||||
@@ -50,10 +50,10 @@ hideToc: true
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Create the Supabase client">
|
||||
<StepHikeCompact.Step step={4}>
|
||||
<StepHikeCompact.Details title="Declare Supabase Environment Variables">
|
||||
|
||||
Create a `/src/lib` directory in your Vue app, create a file called `supabaseClient.js` and add the following code to initialize the Supabase client with your project URL and public API (anon) key:
|
||||
Create a `.env.local` file and populate with your Supabase connection variables:
|
||||
|
||||
<ProjectConfigVariables variable="url" />
|
||||
<ProjectConfigVariables variable="anonKey" />
|
||||
@@ -62,17 +62,42 @@ hideToc: true
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```js name=src/lib/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
<$CodeTabs>
|
||||
|
||||
export const supabase = createClient('https://<project>.supabase.co', '<your-anon-key>')
|
||||
```
|
||||
```text name=.env.local
|
||||
VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
|
||||
VITE_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={5}>
|
||||
<StepHikeCompact.Details title="Create the Supabase client">
|
||||
|
||||
Create a `/src/lib` directory in your Vue app, create a file called `supabaseClient.js` and add the following code to initialize the Supabase client:
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```js name=src/lib/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={6}>
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
|
||||
Replace the existing content in your `App.vue` file with the following code.
|
||||
@@ -109,7 +134,7 @@ hideToc: true
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={6}>
|
||||
<StepHikeCompact.Step step={7}>
|
||||
<StepHikeCompact.Details title="Start the app">
|
||||
|
||||
Start the app and go to http://localhost:5173 in a browser and you should see the list of instruments.
|
||||
|
||||
@@ -367,9 +367,9 @@ enum TransferError: Error {
|
||||
<$CodeTabs>
|
||||
|
||||
```swift name=ProfileView.swift
|
||||
+ import PhotosUI
|
||||
+ import Storage
|
||||
+ import Supabase
|
||||
import PhotosUI
|
||||
import Storage
|
||||
import Supabase
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileView: View {
|
||||
@@ -379,34 +379,34 @@ struct ProfileView: View {
|
||||
|
||||
@State var isLoading = false
|
||||
|
||||
+ @State var imageSelection: PhotosPickerItem?
|
||||
+ @State var avatarImage: AvatarImage?
|
||||
@State var imageSelection: PhotosPickerItem?
|
||||
@State var avatarImage: AvatarImage?
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
+ Section {
|
||||
+ HStack {
|
||||
+ Group {
|
||||
+ if let avatarImage {
|
||||
+ avatarImage.image.resizable()
|
||||
+ } else {
|
||||
+ Color.clear
|
||||
+ }
|
||||
+ }
|
||||
+ .scaledToFit()
|
||||
+ .frame(width: 80, height: 80)
|
||||
+
|
||||
+ Spacer()
|
||||
+
|
||||
+ PhotosPicker(selection: $imageSelection, matching: .images) {
|
||||
+ Image(systemName: "pencil.circle.fill")
|
||||
+ .symbolRenderingMode(.multicolor)
|
||||
+ .font(.system(size: 30))
|
||||
+ .foregroundColor(.accentColor)
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
Section {
|
||||
HStack {
|
||||
Group {
|
||||
if let avatarImage {
|
||||
avatarImage.image.resizable()
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
}
|
||||
.scaledToFit()
|
||||
.frame(width: 80, height: 80)
|
||||
|
||||
Spacer()
|
||||
|
||||
PhotosPicker(selection: $imageSelection, matching: .images) {
|
||||
Image(systemName: "pencil.circle.fill")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.font(.system(size: 30))
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
TextField("Username", text: $username)
|
||||
@@ -440,10 +440,10 @@ struct ProfileView: View {
|
||||
}
|
||||
}
|
||||
})
|
||||
+ .onChange(of: imageSelection) { _, newValue in
|
||||
+ guard let newValue else { return }
|
||||
+ loadTransferable(from: newValue)
|
||||
+ }
|
||||
.onChange(of: imageSelection) { _, newValue in
|
||||
guard let newValue else { return }
|
||||
loadTransferable(from: newValue)
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await getInitialProfile()
|
||||
@@ -467,9 +467,9 @@ struct ProfileView: View {
|
||||
fullName = profile.fullName ?? ""
|
||||
website = profile.website ?? ""
|
||||
|
||||
+ if let avatarURL = profile.avatarURL, !avatarURL.isEmpty {
|
||||
+ try await downloadImage(path: avatarURL)
|
||||
+ }
|
||||
if let avatarURL = profile.avatarURL, !avatarURL.isEmpty {
|
||||
try await downloadImage(path: avatarURL)
|
||||
}
|
||||
|
||||
} catch {
|
||||
debugPrint(error)
|
||||
@@ -481,7 +481,7 @@ struct ProfileView: View {
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
do {
|
||||
+ let imageURL = try await uploadImage()
|
||||
let imageURL = try await uploadImage()
|
||||
|
||||
let currentUser = try await supabase.auth.session.user
|
||||
|
||||
@@ -489,7 +489,7 @@ struct ProfileView: View {
|
||||
username: username,
|
||||
fullName: fullName,
|
||||
website: website,
|
||||
+ avatarURL: imageURL
|
||||
avatarURL: imageURL
|
||||
)
|
||||
|
||||
try await supabase
|
||||
@@ -503,36 +503,36 @@ struct ProfileView: View {
|
||||
}
|
||||
}
|
||||
|
||||
+ private func loadTransferable(from imageSelection: PhotosPickerItem) {
|
||||
+ Task {
|
||||
+ do {
|
||||
+ avatarImage = try await imageSelection.loadTransferable(type: AvatarImage.self)
|
||||
+ } catch {
|
||||
+ debugPrint(error)
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private func downloadImage(path: String) async throws {
|
||||
+ let data = try await supabase.storage.from("avatars").download(path: path)
|
||||
+ avatarImage = AvatarImage(data: data)
|
||||
+ }
|
||||
+
|
||||
+ private func uploadImage() async throws -> String? {
|
||||
+ guard let data = avatarImage?.data else { return nil }
|
||||
+
|
||||
+ let filePath = "\(UUID().uuidString).jpeg"
|
||||
+
|
||||
+ try await supabase.storage
|
||||
+ .from("avatars")
|
||||
+ .upload(
|
||||
+ filePath,
|
||||
+ data: data,
|
||||
+ options: FileOptions(contentType: "image/jpeg")
|
||||
+ )
|
||||
+
|
||||
+ return filePath
|
||||
+ }
|
||||
private func loadTransferable(from imageSelection: PhotosPickerItem) {
|
||||
Task {
|
||||
do {
|
||||
avatarImage = try await imageSelection.loadTransferable(type: AvatarImage.self)
|
||||
} catch {
|
||||
debugPrint(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func downloadImage(path: String) async throws {
|
||||
let data = try await supabase.storage.from("avatars").download(path: path)
|
||||
avatarImage = AvatarImage(data: data)
|
||||
}
|
||||
|
||||
private func uploadImage() async throws -> String? {
|
||||
guard let data = avatarImage?.data else { return nil }
|
||||
|
||||
let filePath = "\(UUID().uuidString).jpeg"
|
||||
|
||||
try await supabase.storage
|
||||
.from("avatars")
|
||||
.upload(
|
||||
filePath,
|
||||
data: data,
|
||||
options: FileOptions(contentType: "image/jpeg")
|
||||
)
|
||||
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@ supabase db diff -f create_employees_table
|
||||
<StepHikeCompact>
|
||||
|
||||
<StepHikeCompact.Step step={3}>
|
||||
<StepHikeCompact.Details title="Start the local database">
|
||||
The new migration file will be used when starting the database locally so you can validate your schema using the local Dashboard.
|
||||
<StepHikeCompact.Details title="Start the local database and apply migrations">
|
||||
Start the local database and then apply the migration file to see your schema changes in the local Dashboard.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
@@ -82,7 +82,7 @@ supabase db diff -f create_employees_table
|
||||
<$CodeTabs>
|
||||
|
||||
```bash name=Terminal
|
||||
supabase start
|
||||
supabase start && supabase migration up
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
@@ -26,7 +26,7 @@ values
|
||||
('Mexico', 'MX');
|
||||
```
|
||||
|
||||
If you want to manage multiple seed files or organize them across different folders, you can configure additional paths or glob patterns in your `config.toml` (see the [next section](#splitting-up-your-seed-data) for details).
|
||||
If you want to manage multiple seed files or organize them across different folders, you can configure additional paths or glob patterns in your `config.toml` (see the [next section](#splitting-up-your-seed-file) for details).
|
||||
|
||||
### Splitting up your seed file
|
||||
|
||||
|
||||
@@ -42,14 +42,13 @@ No, we do not charge for paused projects. Compute hours are only counted for act
|
||||
|
||||
#### How are multiple projects billed under a paid organization?
|
||||
|
||||
We provide a dedicated server for every Supabase project. Each paid organization comes with $10 in Compute Credits to cover one project on the default compute size. Additional projects start at ~$10 a month (billed hourly).
|
||||
We provide a dedicated server for every Supabase project. Each paid organization comes with <Price price="10" /> in Compute Credits to cover one project on the default compute size. Additional projects start at ~<Price price="10" /> a month (billed hourly).
|
||||
|
||||
Running 3 projects in a Pro Plan organization on the default Micro instance:
|
||||
|
||||
- $25 Pro Plan
|
||||
- $30 for 3 projects on the default compute size
|
||||
- $10 Compute credits
|
||||
⇒ $45 / month
|
||||
- <Price price="25" /> Pro Plan
|
||||
- <Price price="30" /> for 3 projects on the default compute size
|
||||
- <Price price="10" /> Compute credits ⇒ <Price price="45" /> / month
|
||||
|
||||
Refer to our [Compute](/docs/guides/platform/manage-your-usage/compute#billing-examples) docs for more examples and insights.
|
||||
|
||||
|
||||
@@ -61,18 +61,18 @@ For usage items without a quota, such as [Compute](/docs/guides/platform/manage-
|
||||
|
||||
The quota is applied to your entire organization, independent of how many projects you launch within that organization. For billing purposes, we sum the usage across all projects in a monthly invoice.
|
||||
|
||||
| Usage Item | Free | Pro/Team | Enterprise |
|
||||
| -------------------------------- | ------------------------ | -------------------------------------------------- | ---------- |
|
||||
| Egress | 5 GB | 250 GB included, then $0.09 per GB | Custom |
|
||||
| Database Size | 500 MB | 8 GB disk per project included, then $0.125 per GB | Custom |
|
||||
| Monthly Active Users | 50,000 MAU | 100,000 MAU included, then $0.00325 per MAU | Custom |
|
||||
| Monthly Active Third-Party Users | 50 MAU | 50 MAU included, then $0.00325 per MAU | Custom |
|
||||
| Monthly Active SSO Users | Unavailable on Free Plan | 50 MAU included, then $0.015 per MAU | Custom |
|
||||
| Storage Size | 1 GB | 100 GB included, then $0.021 per GB | Custom |
|
||||
| Storage Images Transformed | Unavailable on Free Plan | 100 included, then $5 per 1000 | Custom |
|
||||
| Edge Function Invocations | 500,000 | 2 million included, then $2 per million | Custom |
|
||||
| Realtime Message Count | 2 million | 5 million included, then $2.5 per million | Custom |
|
||||
| Realtime Peak Connections | 200 | 500 included, then $10 per 1000 | Custom |
|
||||
| Usage Item | Free | Pro/Team | Enterprise |
|
||||
| -------------------------------- | ------------------------ | ------------------------------------------------------------------- | ---------- |
|
||||
| Egress | 5 GB | 250 GB included, then <Price price="0.09" /> per GB | Custom |
|
||||
| Database Size | 500 MB | 8 GB disk per project included, then <Price price="0.125" /> per GB | Custom |
|
||||
| Monthly Active Users | 50,000 MAU | 100,000 MAU included, then <Price price="0.00325" /> per MAU | Custom |
|
||||
| Monthly Active Third-Party Users | 50 MAU | 50 MAU included, then <Price price="0.00325" /> per MAU | Custom |
|
||||
| Monthly Active SSO Users | Unavailable on Free Plan | 50 MAU included, then <Price price="0.015" /> per MAU | Custom |
|
||||
| Storage Size | 1 GB | 100 GB included, then <Price price="0.021" /> per GB | Custom |
|
||||
| Storage Images Transformed | Unavailable on Free Plan | 100 included, then <Price price="5" /> per 1000 | Custom |
|
||||
| Edge Function Invocations | 500,000 | 2 million included, then <Price price="2" /> per million | Custom |
|
||||
| Realtime Message Count | 2 million | 5 million included, then <Price price="2.5" /> per million | Custom |
|
||||
| Realtime Peak Connections | 200 | 500 included, then <Price price="10" /> per 1000 | Custom |
|
||||
|
||||
You can find a detailed breakdown of all usage items and how they are billed on the [Manage your usage](/docs/guides/platform/manage-your-usage) page.
|
||||
|
||||
|
||||
@@ -16,20 +16,20 @@ In paid organizations, Nano Compute are billed at the same price as Micro Comput
|
||||
|
||||
</Admonition>
|
||||
|
||||
| Compute Size | Hourly Price USD | Monthly Price USD | CPU | Memory | Max DB Size (Recommended)[^2] |
|
||||
| ------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------ | ----------------------------- |
|
||||
| Nano[^3] | $0 | $0 | Shared | Up to 0.5 GB | 500 MB |
|
||||
| Micro | $0.01344 | ~$10 | 2-core ARM (shared) | 1 GB | 10 GB |
|
||||
| Small | $0.0206 | ~$15 | 2-core ARM (shared) | 2 GB | 50 GB |
|
||||
| Medium | $0.0822 | ~$60 | 2-core ARM (shared) | 4 GB | 100 GB |
|
||||
| Large | $0.1517 | ~$110 | 2-core ARM (dedicated) | 8 GB | 200 GB |
|
||||
| XL | $0.2877 | ~$210 | 4-core ARM (dedicated) | 16 GB | 500 GB |
|
||||
| 2XL | $0.562 | ~$410 | 8-core ARM (dedicated) | 32 GB | 1 TB |
|
||||
| 4XL | $1.32 | ~$960 | 16-core ARM (dedicated) | 64 GB | 2 TB |
|
||||
| 8XL | $2.562 | ~$1,870 | 32-core ARM (dedicated) | 128 GB | 4 TB |
|
||||
| 12XL | $3.836 | ~$2,800 | 48-core ARM (dedicated) | 192 GB | 6 TB |
|
||||
| 16XL | $5.12 | ~$3,730 | 64-core ARM (dedicated) | 256 GB | 10 TB |
|
||||
| >16XL | - | [Contact Us](https://supabase.com/dashboard/support/new?category=sales&subject=Enquiry%20about%20larger%20instance%20sizes) | Custom | Custom | Custom |
|
||||
| Compute Size | Hourly Price USD | Monthly Price USD | CPU | Memory | Max DB Size (Recommended)[^2] |
|
||||
| ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------ | ----------------------------- |
|
||||
| Nano[^3] | <Price price="0" /> | <Price price="0" /> | Shared | Up to 0.5 GB | 500 MB |
|
||||
| Micro | <Price price="0.01344" /> | ~<Price price="10" /> | 2-core ARM (shared) | 1 GB | 10 GB |
|
||||
| Small | <Price price="0.0206" /> | ~<Price price="15" /> | 2-core ARM (shared) | 2 GB | 50 GB |
|
||||
| Medium | <Price price="0.0822" /> | ~<Price price="60" /> | 2-core ARM (shared) | 4 GB | 100 GB |
|
||||
| Large | <Price price="0.1517" /> | ~<Price price="110" /> | 2-core ARM (dedicated) | 8 GB | 200 GB |
|
||||
| XL | <Price price="0.2877" /> | ~<Price price="210" /> | 4-core ARM (dedicated) | 16 GB | 500 GB |
|
||||
| 2XL | <Price price="0.562" /> | ~<Price price="410" /> | 8-core ARM (dedicated) | 32 GB | 1 TB |
|
||||
| 4XL | <Price price="1.32" /> | ~<Price price="960" /> | 16-core ARM (dedicated) | 64 GB | 2 TB |
|
||||
| 8XL | <Price price="2.562" /> | ~<Price price="1" />,870 | 32-core ARM (dedicated) | 128 GB | 4 TB |
|
||||
| 12XL | <Price price="3.836" /> | ~<Price price="2" />,800 | 48-core ARM (dedicated) | 192 GB | 6 TB |
|
||||
| 16XL | <Price price="5.12" /> | ~<Price price="3" />,730 | 64-core ARM (dedicated) | 256 GB | 10 TB |
|
||||
| >16XL | - | [Contact Us](https://supabase.com/dashboard/support/new?category=sales&subject=Enquiry%20about%20larger%20instance%20sizes) | Custom | Custom | Custom |
|
||||
|
||||
[^1]: Database max connections are recommended values and can be customized depending on your use case.
|
||||
[^2]: Database size for each compute instance is the default recommendation but the actual performance of your database has many contributing factors, including resources available to it and the size of the data contained within it. See the [shared responsibility model](https://supabase.com/docs/guides/platform/shared-responsibility-model) for more information.
|
||||
@@ -121,14 +121,14 @@ Be aware that increasing IOPS or throughput incurs additional charges.
|
||||
|
||||
When selecting your disk, it's essential to focus on the performance needs of your workload. Here's a comparison of our available disk types:
|
||||
|
||||
| | General Purpose SSD (gp3) | High Performance SSD (io2) |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| **Use Case** | General workloads, development environments, small to medium databases | High-performance needs, large-scale databases, mission-critical applications |
|
||||
| **Max Disk Size** | 16 TB | 60 TB |
|
||||
| **Max IOPS** | 16,000 IOPS (at 32 GB disk size) | 80,000 IOPS (at 80 GB disk size) |
|
||||
| **Throughput** | 125 MB/s (default) to 1,000 MB/s (maximum) | Automatically scales with IOPS |
|
||||
| **Best For** | Great value for most use cases | Low latency and very high IOPS requirements |
|
||||
| **Pricing** | Disk: 8 GB included, then $0.125 per GB<br/>IOPS: 3,000 included, then $0.024 per IOPS<br/>Throughput: 125 MB/s included, then $0.95 per MB/s | Disk: $0.195 per GB<br/>IOPS: $0.119 per IOPS<br/>Throughput: Scales with IOPS at no additional cost |
|
||||
| | General Purpose SSD (gp3) | High Performance SSD (io2) |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Use Case** | General workloads, development environments, small to medium databases | High-performance needs, large-scale databases, mission-critical applications |
|
||||
| **Max Disk Size** | 16 TB | 60 TB |
|
||||
| **Max IOPS** | 16,000 IOPS (at 32 GB disk size) | 80,000 IOPS (at 80 GB disk size) |
|
||||
| **Throughput** | 125 MB/s (default) to 1,000 MB/s (maximum) | Automatically scales with IOPS |
|
||||
| **Best For** | Great value for most use cases | Low latency and very high IOPS requirements |
|
||||
| **Pricing** | Disk: 8 GB included, then <Price price="0.125" /> per GB<br/>IOPS: 3,000 included, then <Price price="0.024" /> per IOPS<br/>Throughput: 125 MB/s included, then <Price price="0.95" /> per MB/s | Disk: <Price price="0.195" /> per GB<br/>IOPS: <Price price="0.119" /> per IOPS<br/>Throughput: Scales with IOPS at no additional cost |
|
||||
|
||||
For general, day-to-day operations, gp3 should be more than enough. If you need high throughput and IOPS for critical systems, io2 will provide the performance required.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ title: 'Credits'
|
||||
|
||||
## Credit balance
|
||||
|
||||
Each organization has a credit balance. Credits are applied to future invoices to reduce the amount due. As long as the credit balance is greater than $0, credits will be used before charging your payment method on file.
|
||||
Each organization has a credit balance. Credits are applied to future invoices to reduce the amount due. As long as the credit balance is greater than <Price price="0" />, credits will be used before charging your payment method on file.
|
||||
|
||||
<Image
|
||||
alt="Subscription upgrade modal"
|
||||
@@ -27,13 +27,13 @@ As an example, if you start a Pro Plan subscription on January 1 and downgrade t
|
||||
|
||||
## Credit top-ups
|
||||
|
||||
You can top up credits at any time, with a maximum of $999 per top-up. These credits do not expire and are non-refundable.
|
||||
You can top up credits at any time, with a maximum of <Price price="999" /> per top-up. These credits do not expire and are non-refundable.
|
||||
|
||||
You may want to consider this option to avoid issues with recurring payments, gain more control over how often your credit card is charged, and potentially make things easier for your accounting department.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If you are interested in larger (> $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="1" />,000) credit packages, [reach out](https://supabase.com/dashboard/support/new?subject=I%20would%20like%20to%20inquire%20about%20larger%20credit%20packages&category=Sales).
|
||||
|
||||
</Admonition>
|
||||
|
||||
|
||||
@@ -42,32 +42,32 @@ Usage is shown as "Auth MFA Phone Hours" on your invoice.
|
||||
|
||||
The project has MFA Phone activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | -------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| MFA Phone Hours | 744 | $75 |
|
||||
| **Subtotal** | | **$110** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$100** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------- |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| MFA Phone Hours | 744 | <Price price="75" /> |
|
||||
| **Subtotal** | | **<Price price="110" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="100" />** |
|
||||
|
||||
### Multiple projects
|
||||
|
||||
All projects have MFA Phone activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | -------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| MFA Phone Hours Project 1 | 744 | $75 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | $10 |
|
||||
| MFA Phone Hours Project 2 | 744 | $10 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 | $10 |
|
||||
| MFA Phone Hours Project 3 | 744 | $10 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$150** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$140** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------- |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| MFA Phone Hours Project 1 | 744 | <Price price="75" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | <Price price="10" /> |
|
||||
| MFA Phone Hours Project 2 | 744 | <Price price="10" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 | <Price price="10" /> |
|
||||
| MFA Phone Hours Project 3 | 744 | <Price price="10" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="150" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="140" />** |
|
||||
@@ -25,21 +25,21 @@ Compute incurred by Preview branches is shown as "Branching Compute Hours" on yo
|
||||
|
||||
The project has a Preview branch "XYZ", that runs for 30 hours, incurring Compute and Egress costs. Disk Size usage remains within the 8 GB included in the subscription plan, so no additional charges apply.
|
||||
|
||||
| Line Item | Costs |
|
||||
| ------------------------------ | --------- |
|
||||
| Pro Plan | $25 |
|
||||
| | |
|
||||
| Compute Hours Small Project 1 | $15 |
|
||||
| Egress Project 1 | $7 |
|
||||
| Disk Size Project 1 | $3 |
|
||||
| | |
|
||||
| Compute Hours Micro Branch XYZ | $0.4 |
|
||||
| Egress Branch XYZ | $1 |
|
||||
| Disk Size Branch XYZ | $0 |
|
||||
| | |
|
||||
| **Subtotal** | **$51.4** |
|
||||
| Compute Credits | -$10 |
|
||||
| **Total** | **$41.4** |
|
||||
| Line Item | Costs |
|
||||
| ------------------------------ | -------------------------- |
|
||||
| Pro Plan | <Price price="25" /> |
|
||||
| | |
|
||||
| Compute Hours Small Project 1 | <Price price="15" /> |
|
||||
| Egress Project 1 | <Price price="7" /> |
|
||||
| Disk Size Project 1 | <Price price="3" /> |
|
||||
| | |
|
||||
| Compute Hours Micro Branch XYZ | <Price price="0.4" /> |
|
||||
| Egress Branch XYZ | <Price price="1" /> |
|
||||
| Disk Size Branch XYZ | <Price price="0" /> |
|
||||
| | |
|
||||
| **Subtotal** | **<Price price="51.4" />** |
|
||||
| Compute Credits | -<Price price="10" /> |
|
||||
| **Total** | **<Price price="41.4" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
@@ -54,10 +54,10 @@ You can view Branching usage on the [organization's usage page](https://supabase
|
||||
zoomable
|
||||
/>
|
||||
|
||||
In the Usage Summary section, you can see how many hours your Preview branches existed during the selected time period. Hover over "Branches Compute Hours" for a detailed breakdown.
|
||||
In the Usage Summary section, you can see how many hours your Preview branches existed during the selected time period. Hover over "Branching Compute Hours" for a detailed breakdown.
|
||||
|
||||
<Image
|
||||
alt="Usage summary Branches Compute Hours"
|
||||
alt="Usage summary Branching Compute Hours"
|
||||
src={{
|
||||
light: '/docs/img/guides/platform/usage-summary-branch-hours--light.png',
|
||||
dark: '/docs/img/guides/platform/usage-summary-branch-hours--dark.png',
|
||||
|
||||
@@ -36,24 +36,24 @@ Usage is shown as "Compute Hours" on your invoice.
|
||||
|
||||
## Compute Credits
|
||||
|
||||
Paid plans include $10 in Compute Credits, which cover one project running on the Micro/Nano Compute size or portions of other Compute sizes. Compute Credits are applied to your Compute costs and are provided to an organization each month. They reset monthly and do not accumulate.
|
||||
Paid plans include <Price price="10" /> in Compute Credits, which cover one project running on the Micro/Nano Compute size or portions of other Compute sizes. Compute Credits are applied to your Compute costs and are provided to an organization each month. They reset monthly and do not accumulate.
|
||||
|
||||
## Pricing
|
||||
|
||||
| Compute Size | Hourly Price USD | Monthly Price USD |
|
||||
| ------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Nano[^1] | $0 | $0 |
|
||||
| Micro | $0.01344 | ~$10 |
|
||||
| Small | $0.0206 | ~$15 |
|
||||
| Medium | $0.0822 | ~$60 |
|
||||
| Large | $0.1517 | ~$110 |
|
||||
| XL | $0.2877 | ~$210 |
|
||||
| 2XL | $0.562 | ~$410 |
|
||||
| 4XL | $1.32 | ~$960 |
|
||||
| 8XL | $2.562 | ~$1,870 |
|
||||
| 12XL | $3.836 | ~$2,800 |
|
||||
| 16XL | $5.12 | ~$3,730 |
|
||||
| >16XL | - | [Contact Us](https://supabase.com/dashboard/support/new?category=sales&subject=Enquiry%20about%20larger%20instance%20sizes) |
|
||||
| Compute Size | Hourly Price USD | Monthly Price USD |
|
||||
| ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Nano[^1] | <Price price="0" /> | <Price price="0" /> |
|
||||
| Micro | <Price price="0.01344" /> | ~<Price price="10" /> |
|
||||
| Small | <Price price="0.0206" /> | ~<Price price="15" /> |
|
||||
| Medium | <Price price="0.0822" /> | ~<Price price="60" /> |
|
||||
| Large | <Price price="0.1517" /> | ~<Price price="110" /> |
|
||||
| XL | <Price price="0.2877" /> | ~<Price price="210" /> |
|
||||
| 2XL | <Price price="0.562" /> | ~<Price price="410" /> |
|
||||
| 4XL | <Price price="1.32" /> | ~<Price price="960" /> |
|
||||
| 8XL | <Price price="2.562" /> | ~<Price price="1,870" /> |
|
||||
| 12XL | <Price price="3.836" /> | ~<Price price="2,800"/> |
|
||||
| 16XL | <Price price="5.12" /> | ~<Price price="3,730"/> |
|
||||
| >16XL | - | [Contact Us](https://supabase.com/dashboard/support/new?category=sales&subject=Enquiry%20about%20larger%20instance%20sizes) |
|
||||
|
||||
[^1]: Compute resources on the Free Plan are subject to change.
|
||||
|
||||
@@ -69,40 +69,40 @@ In paid organizations, Nano Compute are billed at the same price as Micro Comput
|
||||
|
||||
The project runs on the same Compute size throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25"/> |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Multiple projects
|
||||
|
||||
All projects run on the same Compute size throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| Compute Hours Micro Project 2 | 744 | $10 |
|
||||
| Compute Hours Micro Project 3 | 744 | $10 |
|
||||
| **Subtotal** | | **$55** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$45** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| Compute Hours Micro Project 2 | 744 | <Price price="10" /> |
|
||||
| Compute Hours Micro Project 3 | 744 | <Price price="10" /> |
|
||||
| **Subtotal** | | **<Price price="55" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="45" />** |
|
||||
|
||||
### One project on different Compute sizes
|
||||
|
||||
The project's Compute size changes throughout the billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 233 | $3 |
|
||||
| Compute Hours Small Project 1 | 511 | $11 |
|
||||
| **Subtotal** | | **$39** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$29** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Micro Project 1 | 233 | <Price price="3" /> |
|
||||
| Compute Hours Small Project 1 | 511 | <Price price="11" /> |
|
||||
| **Subtotal** | | **<Price price="39" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="29" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Usage is shown as "Custom Domain Hours" on your invoice.
|
||||
|
||||
## Pricing
|
||||
|
||||
$0.0137 per hour ($10 per month).
|
||||
<Price price="0.0137" /> per hour (<Price price="10" /> per month).
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -36,32 +36,32 @@ $0.0137 per hour ($10 per month).
|
||||
|
||||
The project has a custom domain activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| Custom Domain Hours | 744 | $10 |
|
||||
| **Subtotal** | | **$45** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$35** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| Custom Domain Hours | 744 | <Price price="10" /> |
|
||||
| **Subtotal** | | **<Price price="45" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="35" />** |
|
||||
|
||||
### Multiple projects
|
||||
|
||||
All projects have a custom domain activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| Custom Domain Hours Project 1 | 744 | $10 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | $10 |
|
||||
| Custom Domain Hours Project 2 | 744 | $10 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$65** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$55** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| Custom Domain Hours Project 1 | 744 | <Price price="10" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | <Price price="10" /> |
|
||||
| Custom Domain Hours Project 2 | 744 | <Price price="10" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="65" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="55" />** |
|
||||
|
||||
## Optimize usage
|
||||
|
||||
|
||||
@@ -29,24 +29,26 @@ Pricing depends on the [disk type](/docs/guides/platform/compute-and-disk#disk-t
|
||||
|
||||
### General purpose disks (gp3)
|
||||
|
||||
$0.00003288 per IOPS-Hr ($0.024 per IOPS per month). gp3 disks come with a default IOPS of 3,000. You are only charged for provisioned IOPS exceeding these 3,000 IOPS.
|
||||
<Price price="0.00003288" /> per IOPS-Hr (<Price price="0.024" /> per IOPS per month). gp3 disks
|
||||
come with a default IOPS of 3,000. You are only charged for provisioned IOPS exceeding these 3,000
|
||||
IOPS.
|
||||
|
||||
| Plan | Included Disk IOPS | Over-Usage per IOPS per month | Over-Usage per IOPS-Hr |
|
||||
| ---------- | ------------------ | ----------------------------- | ---------------------- |
|
||||
| Pro | 3,000 | $0.024 | $0.00003288 |
|
||||
| Team | 3,000 | $0.024 | $0.00003288 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Included Disk IOPS | Over-Usage per IOPS per month | Over-Usage per IOPS-Hr |
|
||||
| ---------- | ------------------ | ----------------------------- | ---------------------------- |
|
||||
| Pro | 3,000 | <Price price="0.024" /> | <Price price="0.00003288" /> |
|
||||
| Team | 3,000 | <Price price="0.024" /> | <Price price="0.00003288" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
|
||||
### High performance disks (io2)
|
||||
|
||||
$0.000163 per IOPS-Hr ($0.119 per IOPS per month).
|
||||
Unlike general purpose disks, high performance disks are billed from the first provisioned IOPS.
|
||||
<Price price="0.000163" /> per IOPS-Hr (<Price price="0.119" /> per IOPS per month). Unlike general
|
||||
purpose disks, high performance disks are billed from the first provisioned IOPS.
|
||||
|
||||
| Plan | Included Disk IOPS | Usage per IOPS per month | Usage per IOPS-Hr |
|
||||
| ---------- | ------------------ | ------------------------ | ----------------- |
|
||||
| Pro | 0 | $0.119 | $0.000163 |
|
||||
| Team | 0 | $0.119 | $0.000163 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Included Disk IOPS | Usage per IOPS per month | Usage per IOPS-Hr |
|
||||
| ---------- | ------------------ | ------------------------ | -------------------------- |
|
||||
| Pro | 0 | <Price price="0.119" /> | <Price price="0.000163" /> |
|
||||
| Team | 0 | <Price price="0.119" /> | <Price price="0.000163" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -54,29 +56,29 @@ Unlike general purpose disks, high performance disks are billed from the first p
|
||||
|
||||
Project 1 doesn't exceed the included IOPS, so no charges for IOPS apply. Project 2 exceeds the included IOPS by 600, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ---------- | ----------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | $10 |
|
||||
| Disk IOPS Project 1 | 3,000 IOPS | $0 |
|
||||
| | | |
|
||||
| Compute Hours Large Project 2 | 744 hours | $110 |
|
||||
| Disk IOPS Project 2 | 3,600 IOPS | $14.40 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$159.40** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$149.40** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ---------- | ---------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | <Price price="10" /> |
|
||||
| Disk IOPS Project 1 | 3,000 IOPS | <Price price="0" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Project 2 | 744 hours | <Price price="110" /> |
|
||||
| Disk IOPS Project 2 | 3,600 IOPS | <Price price="14.40" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="159.40" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="149.40" />** |
|
||||
|
||||
### Io2
|
||||
|
||||
This disk type is billed from the first IOPS provisioned, meaning for 8000 IOPS.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ---------- | ---------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Large Project 1 | 744 hours | $110 |
|
||||
| Disk IOPS Project 1 | 8,000 IOPS | $952 |
|
||||
| **Subtotal** | | **$1,087** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$1,077** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ---------- | --------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Large Project 1 | 744 hours | <Price price="110" /> |
|
||||
| Disk IOPS Project 1 | 8,000 IOPS | <Price price="952" /> |
|
||||
| **Subtotal** | | **<Price price="1" />,087** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="1" />,077** |
|
||||
@@ -28,13 +28,15 @@ Pricing depends on the [disk type](/docs/guides/platform/compute-and-disk#disk-t
|
||||
|
||||
### General purpose disks (gp3)
|
||||
|
||||
$0.000171 per GB-Hr ($0.125 per GB per month). The primary database of your project gets provisioned with an 8 GB disk. You are only charged for provisioned disk size exceeding these 8 GB.
|
||||
<Price price="0.000171" /> per GB-Hr (<Price price="0.125" /> per GB per month). The primary
|
||||
database of your project gets provisioned with an 8 GB disk. You are only charged for provisioned
|
||||
disk size exceeding these 8 GB.
|
||||
|
||||
| Plan | Included Disk Size | Over-Usage per GB per month | Over-Usage per GB-Hr |
|
||||
| ---------- | ------------------ | --------------------------- | -------------------- |
|
||||
| Pro | 8 GB | $0.125 | $0.000171 |
|
||||
| Team | 8 GB | $0.125 | $0.000171 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Included Disk Size | Over-Usage per GB per month | Over-Usage per GB-Hr |
|
||||
| ---------- | ------------------ | --------------------------- | -------------------------- |
|
||||
| Pro | 8 GB | <Price price="0.125" /> | <Price price="0.000171" /> |
|
||||
| Team | 8 GB | <Price price="0.125" /> | <Price price="0.000171" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
@@ -44,14 +46,14 @@ Launching a Read Replica creates an additional database with its own dedicated d
|
||||
|
||||
### High performance disks (io2)
|
||||
|
||||
$0.000267 per GB-Hr ($0.195 per GB per month).
|
||||
Unlike general purpose disks, high performance disks are billed from the first byte of provisioned disk.
|
||||
<Price price="0.000267" /> per GB-Hr (<Price price="0.195" /> per GB per month). Unlike general
|
||||
purpose disks, high performance disks are billed from the first byte of provisioned disk.
|
||||
|
||||
| Plan | Included Disk size | Usage per GB per month | Usage per GB-Hr |
|
||||
| ---------- | ------------------ | ---------------------- | --------------- |
|
||||
| Pro | 0 GB | $0.195 | $0.000267 |
|
||||
| Team | 0 GB | $0.195 | $0.000267 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Included Disk size | Usage per GB per month | Usage per GB-Hr |
|
||||
| ---------- | ------------------ | ----------------------- | -------------------------- |
|
||||
| Pro | 0 GB | <Price price="0.195" /> | <Price price="0.000267" /> |
|
||||
| Team | 0 GB | <Price price="0.195" /> | <Price price="0.000267" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -59,43 +61,43 @@ Unlike general purpose disks, high performance disks are billed from the first b
|
||||
|
||||
Project 1 and 2 don't exceed the included disk size, so no charges for Disk size apply. Project 3 exceeds the included disk size by 42 GB, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | $10 |
|
||||
| Disk Size Project 1 | 8 GB | $0 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 hours | $10 |
|
||||
| Disk Size Project 2 | 8 GB | $0 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 hours | $10 |
|
||||
| Disk Size Project 3 | 50 GB | $5.25 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$50.25** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$40.25** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | --------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 1 | 8 GB | <Price price="0" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 2 | 8 GB | <Price price="0" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 3 | 50 GB | <Price price="5.25" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="50.25" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="40.25" />** |
|
||||
|
||||
### Io2
|
||||
|
||||
This disk type is billed from the first byte of provisioned disk, meaning for 66 GB across all projects.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | $10 |
|
||||
| Disk Size Project 1 | 8 GB | $1.56 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 hours | $10 |
|
||||
| Disk Size Project 2 | 8 GB | $1.56 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 hours | $10 |
|
||||
| Disk Size Project 3 | 50 GB | $9.75 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$67.87** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$57.87** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | --------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 1 | 8 GB | <Price price="1.56" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 2 | 8 GB | <Price price="1.56" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 hours | <Price price="10" /> |
|
||||
| Disk Size Project 3 | 50 GB | <Price price="9.75" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="67.87" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="57.87" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -29,13 +29,15 @@ Pricing depends on the [disk type](/docs/guides/platform/compute-and-disk#disk-t
|
||||
|
||||
### General purpose disks (gp3)
|
||||
|
||||
$0.00013 per MB/s-Hr ($0.095 per MB/s per month). gp3 disks come with a baseline throughput of 125 MB/s. You are only charged for provisioned throughput exceeding these 125 MB/s.
|
||||
<Price price="0.00013" /> per MB/s-Hr (<Price price="0.095" /> per MB/s per month). gp3 disks come
|
||||
with a baseline throughput of 125 MB/s. You are only charged for provisioned throughput exceeding
|
||||
these 125 MB/s.
|
||||
|
||||
| Plan | Included Disk Throughput | Over-Usage per MB/s per month | Over-Usage per MB/s-Hr |
|
||||
| ---------- | ------------------------ | ----------------------------- | ---------------------- |
|
||||
| Pro | 125 MB/s | $0.095 | $0.00013 |
|
||||
| Team | 125 MB/s | $0.095 | $0.00013 |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
| Plan | Included Disk Throughput | Over-Usage per MB/s per month | Over-Usage per MB/s-Hr |
|
||||
| ---------- | ------------------------ | ----------------------------- | ------------------------- |
|
||||
| Pro | 125 MB/s | <Price price="0.095" /> | <Price price="0.00013" /> |
|
||||
| Team | 125 MB/s | <Price price="0.095" /> | <Price price="0.00013" /> |
|
||||
| Enterprise | Custom | Custom | Custom |
|
||||
|
||||
### High performance disks (io2)
|
||||
|
||||
@@ -45,42 +47,42 @@ There are no charges. Throughput scales with IOPS at no additional cost.
|
||||
|
||||
### No additional throughput configured
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | $10 |
|
||||
| Disk Throughput Project 1 | 125 MB/s | $0 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | <Price price="10" /> |
|
||||
| Disk Throughput Project 1 | 125 MB/s | <Price price="0" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Additional throughput configured
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ----------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | $110 |
|
||||
| Disk Throughput Project 1 | 200 MB/s | $7.13 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$142.13** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$132.13** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | <Price price="110" /> |
|
||||
| Disk Throughput Project 1 | 200 MB/s | <Price price="7.13" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="142.13" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="132.13" />** |
|
||||
|
||||
### Additional throughput configured with Read Replica
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ----------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | $110 |
|
||||
| Disk Throughput Project 1 | 200 MB/s | $7.13 |
|
||||
| | | |
|
||||
| Compute Hours Large Replica | 744 hours | $110 |
|
||||
| Disk Throughput Replica | 200 MB/s | $7.13 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$259.26** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$249.26** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | <Price price="110" /> |
|
||||
| Disk Throughput Project 1 | 200 MB/s | <Price price="7.13" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Replica | 744 hours | <Price price="110" /> |
|
||||
| Disk Throughput Replica | 200 MB/s | <Price price="7.13" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="259.26" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="249.26" />** |
|
||||
@@ -13,14 +13,14 @@ Edge Function Invocations are billed using Package pricing, with each package re
|
||||
|
||||
### Example
|
||||
|
||||
For simplicity, let's assume a package size of 1 million and a charge of $2 per package without a free quota.
|
||||
For simplicity, let's assume a package size of 1 million and a charge of <Price price="2" /> per package without a free quota.
|
||||
|
||||
| Invocations | Packages Billed | Costs |
|
||||
| ----------- | --------------- | ----- |
|
||||
| 999,999 | 1 | $2 |
|
||||
| 1,000,000 | 1 | $2 |
|
||||
| 1,000,001 | 2 | $4 |
|
||||
| 1,500,000 | 2 | $4 |
|
||||
| Invocations | Packages Billed | Costs |
|
||||
| ----------- | --------------- | ------------------- |
|
||||
| 999,999 | 1 | <Price price="2" /> |
|
||||
| 1,000,000 | 1 | <Price price="2" /> |
|
||||
| 1,000,001 | 2 | <Price price="4" /> |
|
||||
| 1,500,000 | 2 | <Price price="4" /> |
|
||||
|
||||
### Usage on your invoice
|
||||
|
||||
@@ -36,27 +36,27 @@ Usage is shown as "Function Invocations" on your invoice.
|
||||
|
||||
The organization's function invocations are within the quota, so no charges apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | --------------------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Function Invocations | 1,800,000 invocations | $0 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | --------------------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Function Invocations | 1,800,000 invocations | <Price price="0" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Exceeding quota
|
||||
|
||||
The organization's function invocations exceed the quota by 1.4 million, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | --------------------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Function Invocations | 3,400,000 invocations | $4 |
|
||||
| **Subtotal** | | **$39** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$29** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | --------------------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Function Invocations | 3,400,000 invocations | <Price price="4" /> |
|
||||
| **Subtotal** | | **<Price price="39" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="29" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -59,14 +59,15 @@ Usage is shown as "Egress GB" on your invoice.
|
||||
|
||||
## Pricing
|
||||
|
||||
$0.09 per GB per month. You are only charged for usage exceeding your subscription plan's quota.
|
||||
<Price price="0.09" /> per GB per month. You are only charged for usage exceeding your subscription plan's
|
||||
quota.
|
||||
|
||||
| Plan | Unified Egress Quota | Over-Usage per month |
|
||||
| ---------- | -------------------- | -------------------- |
|
||||
| Free | 5 GB | - |
|
||||
| Pro | 250 GB | $0.09 per GB |
|
||||
| Team | 250 GB | $0.09 per GB |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Unified Egress Quota | Over-Usage per month |
|
||||
| ---------- | -------------------- | ----------------------------- |
|
||||
| Free | 5 GB | - |
|
||||
| Pro | 250 GB | <Price price="0.09" /> per GB |
|
||||
| Team | 250 GB | <Price price="0.09" /> per GB |
|
||||
| Enterprise | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -74,27 +75,27 @@ $0.09 per GB per month. You are only charged for usage exceeding your subscripti
|
||||
|
||||
The organization's Egress usage is within the quota, so no charges for Egress apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------- | --------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Egress | 200 GB | $0 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------- | --------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Egress | 200 GB | <Price price="0" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Exceeding quota
|
||||
|
||||
The organization's Egress usage exceeds the quota by 50 GB, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------- | --------- | --------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Egress | 300 GB | $4.5 |
|
||||
| **Subtotal** | | **$39.5** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$29.5** |
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------- | --------- | -------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Egress | 300 GB | <Price price="4.5" /> |
|
||||
| **Subtotal** | | **<Price price="39.5" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="29.5" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Usage is shown as "IPv4 Hours" on your invoice.
|
||||
|
||||
## Pricing
|
||||
|
||||
$0.0055 per hour ($4 per month).
|
||||
<Price price="0.0055" /> per hour (<Price price="4" /> per month).
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -42,56 +42,56 @@ $0.0055 per hour ($4 per month).
|
||||
|
||||
The project has the IPv4 add-on enabled throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| IPv4 Hours | 744 | $4 |
|
||||
| **Subtotal** | | **$39** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$29** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| IPv4 Hours | 744 | <Price price="4" /> |
|
||||
| **Subtotal** | | **<Price price="39" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="29" />** |
|
||||
|
||||
### Multiple projects
|
||||
|
||||
All projects have the IPv4 add-on enabled throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | $10 |
|
||||
| IPv4 Hours Project 1 | 744 | $4 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | $10 |
|
||||
| IPv4 Hours Project 2 | 744 | $4 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 | $10 |
|
||||
| IPv4 Hours Project 3 | 744 | $4 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$67** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$57** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 | <Price price="10" /> |
|
||||
| IPv4 Hours Project 1 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 2 | 744 | <Price price="10" /> |
|
||||
| IPv4 Hours Project 2 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 3 | 744 | <Price price="10" /> |
|
||||
| IPv4 Hours Project 3 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="67" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="57" />** |
|
||||
|
||||
### One project with Read Replicas
|
||||
|
||||
The project has two Read Replicas and the IPv4 add-on enabled throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 | $15 |
|
||||
| IPv4 Hours Project 1 | 744 | $4 |
|
||||
| | | |
|
||||
| Compute Hours Small Replica 1 | 744 | $15 |
|
||||
| IPv4 Hours Replica 1 | 744 | $4 |
|
||||
| | | |
|
||||
| Compute Hours Small Replica 2 | 744 | $15 |
|
||||
| IPv4 Hours Replica 2 | 744 | $4 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$82** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$72** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------ |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 | <Price price="15" /> |
|
||||
| IPv4 Hours Project 1 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Replica 1 | 744 | <Price price="15" /> |
|
||||
| IPv4 Hours Replica 1 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Replica 2 | 744 | <Price price="15" /> |
|
||||
| IPv4 Hours Replica 2 | 744 | <Price price="4" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="82" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="72" />** |
|
||||
|
||||
## Optimize usage
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Usage is shown as "Log Drain Hours" on your invoice.
|
||||
|
||||
### Pricing
|
||||
|
||||
Log Drains are available as a project Add-On for all Team and Enterprise users. Each Log Drain costs $0.0822 per hour ($60 per month).
|
||||
Log Drains are available as a project Add-On for all Team and Enterprise users. Each Log Drain costs <Price price="0.0822" /> per hour (<Price price="60" /> per month).
|
||||
|
||||
## Log Drain Events
|
||||
|
||||
@@ -40,12 +40,12 @@ Log Drain Events are billed using Package pricing, with each package representin
|
||||
|
||||
#### Example
|
||||
|
||||
| Events | Packages Billed | Costs |
|
||||
| --------- | --------------- | ----- |
|
||||
| 999,999 | 1 | $0.2 |
|
||||
| 1,000,000 | 1 | $0.2 |
|
||||
| 1,000,001 | 2 | $0.4 |
|
||||
| 1,500,000 | 2 | $0.4 |
|
||||
| Events | Packages Billed | Costs |
|
||||
| --------- | --------------- | --------------------- |
|
||||
| 999,999 | 1 | <Price price="0.2" /> |
|
||||
| 1,000,000 | 1 | <Price price="0.2" /> |
|
||||
| 1,000,001 | 2 | <Price price="0.4" /> |
|
||||
| 1,500,000 | 2 | <Price price="0.4" /> |
|
||||
|
||||
#### Usage on your invoice
|
||||
|
||||
@@ -53,29 +53,29 @@ Usage is shown as "Log Drain Events" on your invoice.
|
||||
|
||||
### Pricing
|
||||
|
||||
$0.2 per 1 million events.
|
||||
<Price price="0.2" /> per 1 million events.
|
||||
|
||||
## Billing example
|
||||
|
||||
The project has two log drains configured throughout the entire billing cycle with 800,000 and 1.6 million events each. In this example we assume that the organization is exceeding its Unified Egress Quota, so charges for Egress apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ------------------ | ----------- |
|
||||
| Team Plan | 1 | $599 |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | $10 |
|
||||
| | | |
|
||||
| Log Drain Hours Drain 1 | 744 hours | $60 |
|
||||
| Log Drain Events Drain 1 | 800,000 events | $0.2 |
|
||||
| Egress Drain 1 | 2 GB | $0.18 |
|
||||
| | | |
|
||||
| Log Drain Hours Drain 2 | 744 hours | $60 |
|
||||
| Log Drain Events Drain 2 | 1.6 million events | $0.4 |
|
||||
| Egress Drain 2 | 4 GB | $0.36 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$730.14** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$720.14** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | ------------------ | ---------------------------- |
|
||||
| Team Plan | 1 | <Price price="599" /> |
|
||||
| | | |
|
||||
| Compute Hours Micro Project 1 | 744 hours | <Price price="10" /> |
|
||||
| | | |
|
||||
| Log Drain Hours Drain 1 | 744 hours | <Price price="60" /> |
|
||||
| Log Drain Events Drain 1 | 800,000 events | <Price price="0.2" /> |
|
||||
| Egress Drain 1 | 2 GB | <Price price="0.18" /> |
|
||||
| | | |
|
||||
| Log Drain Hours Drain 2 | 744 hours | <Price price="60" /> |
|
||||
| Log Drain Events Drain 2 | 1.6 million events | <Price price="0.4" /> |
|
||||
| Egress Drain 2 | 4 GB | <Price price="0.36" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="730.14" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="720.14" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -75,11 +75,11 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
</Admonition>
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | ------------------ |
|
||||
| Pro | 50 | $0.015 per SSO MAU |
|
||||
| Team | 50 | $0.015 per SSO MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------ | ----------------------------------- |
|
||||
| Pro | 50 | <Price price="0.015" /> per SSO MAU |
|
||||
| Team | 50 | <Price price="0.015" /> per SSO MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -87,27 +87,27 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
The organization's SSO MAU usage for the billing cycle is within the quota, so no charges apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------------ | ---------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active SSO Users | 37 SSO MAU | $0 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------------ | ---------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active SSO Users | 37 SSO MAU | <Price price="0" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Exceeding quota
|
||||
|
||||
The organization's SSO MAU usage for the billing cycle exceeds the quota by 10, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------------ | ---------- | ---------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active SSO Users | 60 SSO MAU | $0.15 |
|
||||
| **Subtotal** | | **$35.15** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25.15** |
|
||||
| Line Item | Units | Costs |
|
||||
| ------------------------ | ---------- | --------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active SSO Users | 60 SSO MAU | <Price price="0.15" /> |
|
||||
| **Subtotal** | | **<Price price="35.15" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25.15" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
+22
-22
@@ -72,12 +72,12 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
</Admonition>
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------- | ---------------------------- |
|
||||
| Free | 50,000 | - |
|
||||
| Pro | 100,000 | $0.00325 per Third-Party MAU |
|
||||
| Team | 100,000 | $0.00325 per Third-Party MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------- | --------------------------------------------- |
|
||||
| Free | 50,000 | - |
|
||||
| Pro | 100,000 | <Price price="0.00325" /> per Third-Party MAU |
|
||||
| Team | 100,000 | <Price price="0.00325" /> per Third-Party MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -85,27 +85,27 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
The organization's Third-Party MAU usage for the billing cycle is within the quota, so no charges apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------------------- | ---------------------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active Third-Party Users | 37,000 Third-Party MAU | $0 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------------------- | ---------------------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active Third-Party Users | 37,000 Third-Party MAU | <Price price="0" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Exceeding quota
|
||||
|
||||
The organization's Third-Party MAU usage for the billing cycle exceeds the quota by 4950, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------------------- | ----------------------- | ----------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active Third-Party Users | 130,000 Third-Party MAU | $97.50 |
|
||||
| **Subtotal** | | **$132.50** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$122.50** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------------------- | ----------------------- | ---------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active Third-Party Users | 130,000 Third-Party MAU | <Price price="97.50" /> |
|
||||
| **Subtotal** | | **<Price price="132.50" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="122.50" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -67,12 +67,12 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
</Admonition>
|
||||
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------- | ---------------- |
|
||||
| Free | 50,000 | - |
|
||||
| Pro | 100,000 | $0.00325 per MAU |
|
||||
| Team | 100,000 | $0.00325 per MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
| Plan | Quota | Over-Usage |
|
||||
| ---------- | ------- | --------------------------------- |
|
||||
| Free | 50,000 | - |
|
||||
| Pro | 100,000 | <Price price="0.00325" /> per MAU |
|
||||
| Team | 100,000 | <Price price="0.00325" /> per MAU |
|
||||
| Enterprise | Custom | Custom |
|
||||
|
||||
## Billing examples
|
||||
|
||||
@@ -80,27 +80,27 @@ The count resets at the start of each billing cycle.
|
||||
|
||||
The organization's MAU usage for the billing cycle is within the quota, so no charges apply.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | ---------- | ------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active Users | 23,000 MAU | $0 |
|
||||
| **Subtotal** | | **$35** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$25** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | ---------- | ------------------------ |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active Users | 23,000 MAU | <Price price="0" /> |
|
||||
| **Subtotal** | | **<Price price="35" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="25" />** |
|
||||
|
||||
### Exceeding quota
|
||||
|
||||
The organization's MAU usage for the billing cycle exceeds the quota by 60,000, incurring charges for this additional usage.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | ----------- | -------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| Compute Hours Micro | 744 hours | $10 |
|
||||
| Monthly Active Users | 160,000 MAU | $195 |
|
||||
| **Subtotal** | | **$230** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$220** |
|
||||
| Line Item | Units | Costs |
|
||||
| -------------------- | ----------- | ------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| Compute Hours Micro | 744 hours | <Price price="10" /> |
|
||||
| Monthly Active Users | 160,000 MAU | <Price price="195" /> |
|
||||
| **Subtotal** | | **<Price price="230" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="220" />** |
|
||||
|
||||
## View usage
|
||||
|
||||
|
||||
@@ -36,32 +36,32 @@ Usage is shown as "Point-in-time recovery Hours" on your invoice.
|
||||
|
||||
The project has PITR with a recovery retention period of 7 days activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | -------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| Compute Hours Small Project 1 | 744 | $15 |
|
||||
| PITR Hours | 744 | $100 |
|
||||
| **Subtotal** | | **$140** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$130** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------- |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| Compute Hours Small Project 1 | 744 | <Price price="15" /> |
|
||||
| PITR Hours | 744 | <Price price="100" /> |
|
||||
| **Subtotal** | | **<Price price="140" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="130" />** |
|
||||
|
||||
### Multiple projects
|
||||
|
||||
All projects have PITR with a recovery retention period of 14 days activated throughout the entire billing cycle.
|
||||
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | -------- |
|
||||
| Pro Plan | - | $25 |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 | $15 |
|
||||
| PITR Hours Project 1 | 744 | $200 |
|
||||
| | | |
|
||||
| Compute Hours Small Project 2 | 744 | $15 |
|
||||
| PITR Hours Project 2 | 744 | $200 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$455** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$445** |
|
||||
| Line Item | Hours | Costs |
|
||||
| ----------------------------- | ----- | ------------------------- |
|
||||
| Pro Plan | - | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 | <Price price="15" /> |
|
||||
| PITR Hours Project 1 | 744 | <Price price="200" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Project 2 | 744 | <Price price="15" /> |
|
||||
| PITR Hours Project 2 | 744 | <Price price="200" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="455" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="445" />** |
|
||||
|
||||
## Optimize usage
|
||||
|
||||
|
||||
@@ -38,49 +38,49 @@ Compute incurred by Read Replicas is shown as "Replica Compute Hours" on your in
|
||||
|
||||
The project has one Read Replica and no IPv4 and no additional Disk IOPS and Disk Throughput configured.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 hours | $15 |
|
||||
| Disk Size Project 1 | 8 GB | $0 |
|
||||
| | | |
|
||||
| Compute Hours Small Replica | 744 hours | $15 |
|
||||
| Disk Size Replica | 10 GB | $1.25 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$56.25** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$46.25** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | --------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Project 1 | 744 hours | <Price price="15" /> |
|
||||
| Disk Size Project 1 | 8 GB | <Price price="0" /> |
|
||||
| | | |
|
||||
| Compute Hours Small Replica | 744 hours | <Price price="15" /> |
|
||||
| Disk Size Replica | 10 GB | <Price price="1.25" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="56.25" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="46.25" />** |
|
||||
|
||||
### Additional resources configured
|
||||
|
||||
The project has two Read Replicas and IPv4 and additional Disk IOPS and Disk Throughput configured.
|
||||
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ----------- |
|
||||
| Pro Plan | 1 | $25 |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | $110 |
|
||||
| Disk Size Project 1 | 8 GB | $0 |
|
||||
| Disk IOPS Project 1 | 3600 | $14.40 |
|
||||
| Disk Throughput Project 1 | 200 MB/s | $7.13 |
|
||||
| IPv4 Hours Project 1 | 744 hours | $4 |
|
||||
| | | |
|
||||
| Compute Hours Large Replica 1 | 744 hours | $110 |
|
||||
| Disk Size Replica 1 | 10 GB | $1.25 |
|
||||
| Disk IOPS Replica 1 | 3600 | $14.40 |
|
||||
| Disk Throughput Replica 1 | 200 MB/s | $7.13 |
|
||||
| IPv4 Hours Replica 1 | 744 hours | $4 |
|
||||
| | | |
|
||||
| Compute Hours Large Replica 2 | 744 hours | $110 |
|
||||
| Disk Size Replica 2 | 10 GB | $1.25 |
|
||||
| Disk IOPS Replica 2 | 3600 | $14.40 |
|
||||
| Disk Throughput Replica 2 | 200 MB/s | $7.13 |
|
||||
| IPv4 Hours Replica 2 | 744 hours | $4 |
|
||||
| | | |
|
||||
| **Subtotal** | | **$434.09** |
|
||||
| Compute Credits | | -$10 |
|
||||
| **Total** | | **$424.09** |
|
||||
| Line Item | Units | Costs |
|
||||
| ----------------------------- | --------- | ---------------------------- |
|
||||
| Pro Plan | 1 | <Price price="25" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Project 1 | 744 hours | <Price price="110" /> |
|
||||
| Disk Size Project 1 | 8 GB | <Price price="0" /> |
|
||||
| Disk IOPS Project 1 | 3600 | <Price price="14.40" /> |
|
||||
| Disk Throughput Project 1 | 200 MB/s | <Price price="7.13" /> |
|
||||
| IPv4 Hours Project 1 | 744 hours | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Replica 1 | 744 hours | <Price price="110" /> |
|
||||
| Disk Size Replica 1 | 10 GB | <Price price="1.25" /> |
|
||||
| Disk IOPS Replica 1 | 3600 | <Price price="14.40" /> |
|
||||
| Disk Throughput Replica 1 | 200 MB/s | <Price price="7.13" /> |
|
||||
| IPv4 Hours Replica 1 | 744 hours | <Price price="4" /> |
|
||||
| | | |
|
||||
| Compute Hours Large Replica 2 | 744 hours | <Price price="110" /> |
|
||||
| Disk Size Replica 2 | 10 GB | <Price price="1.25" /> |
|
||||
| Disk IOPS Replica 2 | 3600 | <Price price="14.40" /> |
|
||||
| Disk Throughput Replica 2 | 200 MB/s | <Price price="7.13" /> |
|
||||
| IPv4 Hours Replica 2 | 744 hours | <Price price="4" /> |
|
||||
| | | |
|
||||
| **Subtotal** | | **<Price price="434.09" />** |
|
||||
| Compute Credits | | -<Price price="10" /> |
|
||||
| **Total** | | **<Price price="424.09" />** |
|
||||
|
||||
## FAQ
|
||||
|
||||
|
||||
Loaded 100 of 792 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user