Merge pull request #13482 from supabase/master

Prod deploy dashboard
This commit is contained in:
Joshen Lim authored and GitHub committed 2023-04-06 14:12:19 +08:00
commit 71d8fabad4
112 files changed
+45602 -27820

No files matched your search

+2
View File
@@ -121,3 +121,5 @@ typings/
**/supabase/.temp
apps/new-docs/*
gcloud.json
@@ -115,6 +115,13 @@ const home = [
level: 'reference_csharp',
community: true,
},
{
label: 'Swift',
icon: '/img/icons/menu/reference-swift',
href: '/reference/swift/introduction',
level: 'reference_swift',
community: true,
},
{
label: 'Tools',
},
@@ -28,6 +28,12 @@ export const REFERENCES: References = {
versions: ['v0'],
icon: '/docs/img/libraries/c-sharp-icon.svg',
},
swift: {
name: 'Swift',
library: 'supabase-swift',
versions: ['v1'],
icon: '/docs/img/libraries/swift-icon.svg',
},
cli: {
name: 'CLI',
library: undefined,
@@ -284,7 +290,7 @@ export const auth = {
url: '/guides/auth/enterprise-sso',
items: [
{
name: 'SAML 2.0 (Beta)',
name: 'SAML 2.0',
url: '/guides/auth/sso/auth-sso-saml',
},
],
@@ -828,6 +834,13 @@ export const self_hosting = {
{ name: 'Configuration', url: '/guides/self-hosting/realtime/config' },
],
},
{
name: 'Analytics Server',
items: [
{ name: 'Reference', url: '/reference/self-hosting-analytics/introduction', items: [] },
{ name: 'Configuration', url: '/guides/self-hosting/analytics/config', items: [] },
],
},
],
}
@@ -937,6 +950,13 @@ export const reference = {
level: 'reference_python',
icon: '/img/icons/menu/reference-python',
},
{
name: 'supbase-swift',
url: '/reference/swift/start',
level: 'reference_swift',
items: [],
icon: '/img/icons/menu/reference-swift',
},
// {
// name: 'supabase-python',
// url: '/reference/python/start',
@@ -1006,6 +1026,13 @@ export const reference_python_v2 = {
parent: '/reference',
}
export const reference_swift_v1 = {
icon: 'reference-swift',
title: 'swift',
url: 'guides/reference/swift',
parent: '/reference',
}
export const reference_cli = {
icon: 'reference-cli',
title: 'Supabase CLI',
@@ -1034,12 +1061,19 @@ export const reference_self_hosting_storage = {
}
export const reference_self_hosting_realtime = {
icon: 'reference-auth',
icon: 'reference-realtime',
title: 'Self-Hosting Realtime',
url: '/guides/reference/self-hosting/realtime',
parent: '/reference',
}
export const reference_self_hosting_analytics = {
icon: 'reference-analytics',
title: 'Self-Hosting Analytics',
url: '/guides/reference/self-hosting/analytics',
parent: '/reference',
}
// export const reference: [
// {
// label: 'Official'
@@ -1106,6 +1140,13 @@ export const references = [
icon: '/docs/img/icons/c-sharp-icon.svg',
url: '/reference/csharp/start',
},
{
label: 'supabase-swift',
versions: ['v1'],
description: 'something about the reference',
icon: '/docs/img/icons/swift-icon.svg',
url: '/reference/swift/start',
},
],
},
{
@@ -15,6 +15,8 @@ import spec_dart_v0 from '~/../../spec/supabase_dart_v0.yml' assert { type: 'yml
import spec_csharp_v0 from '~/../../spec/supabase_csharp_v0.yml' assert { type: 'yml' }
// @ts-expect-error
import spec_python_v2 from '~/../../spec/supabase_py_v2.yml' assert { type: 'yml' }
// @ts-expect-error
import spec_swift_v1 from '~/../../spec/supabase_swift_v1.yml' assert { type: 'yml' }
// import { gen_v3 } from '~/lib/refGenerator/helpers'
import apiCommonSections from '~/../../spec/common-api-sections.json'
@@ -22,6 +24,7 @@ import cliCommonSections from '~/../../spec/common-cli-sections.json'
import libCommonSections from '~/../../spec/common-client-libs-sections.json'
import authServerCommonSections from '~/../../spec/common-self-hosting-auth-sections.json'
import realtimeServerCommonSections from '~/../../spec/common-self-hosting-realtime-sections.json'
import analyticsServerCommonSections from '~/../../spec/common-self-hosting-analytics-sections.json'
import storageServerCommonSections from '~/../../spec/common-self-hosting-storage-sections.json'
import { flattenSections } from '~/lib/helpers'
import NavigationMenuHome from './HomeMenu'
@@ -54,22 +57,26 @@ export type RefIdOptions =
| 'reference_dart_v1'
| 'reference_csharp_v0'
| 'reference_python_v2'
| 'reference_swift_v1'
| 'reference_cli'
| 'reference_api'
| 'reference_self_hosting_auth'
| 'reference_self_hosting_storage'
| 'reference_self_hosting_realtime'
| 'reference_self_hosting_analytics'
export type RefKeyOptions =
| 'javascript'
| 'dart'
| 'csharp'
| 'python'
| 'swift'
| 'cli'
| 'api'
| 'self-hosting-auth'
| 'self-hosting-storage'
| 'self-hosting-realtime'
| 'self-hosting-analytics'
const NavigationMenu = () => {
const router = useRouter()
@@ -135,10 +142,14 @@ const NavigationMenu = () => {
case url.includes(`/docs/reference/csharp`) && url:
menuState.setMenuLevelId('reference_csharp_v0')
break
// puthon v2 (latest)
// python v2 (latest)
case url.includes(`/docs/reference/python`) && url:
menuState.setMenuLevelId('reference_python_v2')
break
// swift v1 (latest)
case url.includes(`/docs/reference/swift`) && url:
menuState.setMenuLevelId('reference_swift_v1')
break
case url.includes(`/docs/reference/cli/config`) && url:
menuState.setMenuLevelId('supabase_cli')
break
@@ -157,6 +168,9 @@ const NavigationMenu = () => {
case url.includes(`/docs/reference/self-hosting-realtime`) && url:
menuState.setMenuLevelId('reference_self_hosting_realtime')
break
case url.includes(`/docs/reference/self-hosting-analytics`) && url:
menuState.setMenuLevelId('reference_self_hosting_analytics')
break
default:
break
@@ -195,11 +209,13 @@ const NavigationMenu = () => {
const isReference_Dart_V1 = 'reference_dart_v1' === level
const isReference_Csharp_V0 = 'reference_csharp_v0' === level
const isReference_Python_V2 = 'reference_python_v2' === level
const isReference_Swift_V1 = 'reference_swift_v1' === level
const isReference_Cli = 'reference_cli' === level
const isReference_Api = 'reference_api' === level
const isReference_Self_Hosting_Auth = 'reference_self_hosting_auth' === level
const isReference_Self_Hosting_Storage = 'reference_self_hosting_storage' === level
const isReference_Self_Hosting_Realtime = 'reference_self_hosting_realtime' === level
const isReference_Self_Hosting_Analytics = 'reference_self_hosting_analytics' === level
return (
<div className={['flex relative', 'justify-center lg:justify-start'].join(' ')}>
@@ -263,7 +279,14 @@ const NavigationMenu = () => {
lib="csharp"
spec={spec_csharp_v0}
/>
<NavigationMenuRefList
key={'reference-swift-menu-v1'}
id={'reference_swift_v1'}
active={isReference_Swift_V1}
commonSections={libCommonSections}
lib="swift"
spec={spec_swift_v1}
/>
<NavigationMenuRefList
key={'reference-python-menu-v2'}
id={'reference_python_v2'}
@@ -309,6 +332,13 @@ const NavigationMenu = () => {
commonSections={realtimeServerCommonSections}
lib="self-hosting-realtime"
/>
<NavigationMenuRefList
key={'reference-self-hosting-analytics-menu'}
id={'reference_self_hosting_analytics'}
active={isReference_Self_Hosting_Analytics}
commonSections={analyticsServerCommonSections}
lib="self-hosting-analytics"
/>
</div>
)
}
@@ -36,7 +36,7 @@ const NavigationMenuGuideList: React.FC<Props> = ({ id, active, value }) => {
type={value ? 'multiple' : 'single'}
value={value ?? firstLevelRoute}
className={[
'transition-all ml-8 duration-150 ease-out',
'transition-all duration-150 ease-out',
// enabled
active && 'opacity-100 ml-0 delay-150',
// level === 'home' && 'ml-12',
@@ -0,0 +1,108 @@
---
id: introduction
title: Introduction
hideTitle: true
---
<div className="flex items-start gap-6 not-prose" id="introduction">
<img src="/docs/img/icons/menu/reference-analytics.svg" className="w-8 h-8 rounded" />
<div className="flex flex-col gap-2">
<h1 className="text-3xl text-scale-1200 m-0">Self-Hosting Analytics</h1>
</div>
</div>
<RefSubLayout.EducationRow>
<RefSubLayout.Details>
The Supabase Analytics server is a Logflare self-hostable instance that manages the ingestion and query pipelines for searching and aggregating structured analytics events.
When self-hosting the Analytics server, the full logging experience matching that of the Supabase Platform is available in the Studio instance, allowing for an integrated and enhanced development experience.
However, it's important to note that certain [differences](#differences) may arise due to the platform's infrastructure.
<Admonition type="info" label="Logflare Technical Docs">
All logflare technical docs are available at
[https://docs.logflare.app](https://docs.logflare.app)
</Admonition>
## Getting Started
Using the example [self-hosting stack based on docker-compose](https://github.com/supabase/supabase/tree/master/docker), you include the logging related services using the following command
```bash
# assuming you clone the supabase/supabase repo.
cd docker
docker compose -f docker-compose.yml -f docker-compose-logging.yml up
```
This would include two additional docker services to your compose stack: Logflare and Vector.
<Admonition type="info" label="Self-hosting">
Read more about [self-hosting Logflare](https://docs.logflare.app/self-hosting) as your analytics
server.
</Admonition>
## Differences
API logs rely on Kong instead of the Supabase Cloud API Gateway. Logs from Kong are not enriched with platform-only data.
Within the self-hosted setup, all logs are routed to Logflare via Vector. As Kong routes API requests to PostgREST, self-hosted or local deployments will result in Kong request logs instead.
This would result in differences in the log event metadata between self-hosted API requests and Supabase Platform requests.
## BigQuery
All log event data is stored in and queried from BigQuery. To use the Analytics server with Supabase you'll need a Google Cloud Platform account for access to BigQuery.
Make sure to set the `GOOGLE_DATASET_ID_APPEND`, `GOOGLE_PROJECT_ID` and `GOOGLE_PROJECT_NUMBER` environment variables.
Download your Google Cloud API JWT and store it under gcloud.json in your working directory.
<Admonition>
You must also enable billing on your Google Cloud project, as the streaming inserts feature is
required.
</Admonition>
## Production Recommendations
To self-host in a production setting, we recommend performing the following for a better experience.
### Ensure that Logflare is behind a firewall and restrict all network access to it besides safe requests.
Self-hosted Logflare has UI authentication disabled and is intended for exposure to the internet. We recommend restricting access to the dashboard, accessible at the `/dashboard` path.
If dashboard access is required for managing sources, we recommend having an authentication layer, such as a VPN.
### Use a different Postgres Database to store Logflare data.
Logflare requires a Postgres database to function. However, if there is an issue with you self-hosted Postgres service, you would not be able to debug it as it would also bring Logflare down together.
The self-hosted example is only used as a minimal example on running the entire stack, however it is not recommended to use the same database server for both production and observability.
</RefSubLayout.Details>
<RefSubLayout.Examples>
### Client libraries
- [JavaScript - Pino Transport](https://github.com/Logflare/pino-logflare)
- [Elixir](https://github.com/Logflare/logflare_api_client)
- [Elixir - Logger Backend](https://github.com/Logflare/logflare_logger_backend)
- [Erlang](https://github.com/Logflare/logflare_erl)
- [Erlang - Lager Backend](https://github.com/Logflare/logflare_lager_backend)
- [Cloudflare Worker](https://gist.github.com/chasers/c7a220e91820a1084b27fcfdb18ad6bd)
### Integrations
- [Fly - Logs](https://github.com/Logflare/fly-log-shipper)
- [Vercel Integration - Logs](https://vercel.com/integrations/logflare)
- [Cloudflare App - Logs](https://www.cloudflare.com/apps/logflare/install)
### Additional links
- [Source code](https://github.com/logflare/logflare)
- [Analytics guides](/docs/guides/analytics) - TODO
- [OpenAPI docs](https://logflare.app/api/openapi)
- [Supabase Acquires Logflare](https://supabase.com/blog/supabase-acquires-logflare)
- [Logflare self-hosting docs](https://docs.logflare.app/self-hosting)
</RefSubLayout.Examples>
</RefSubLayout.EducationRow>
+29
View File
@@ -0,0 +1,29 @@
---
id: introduction
title: Introduction
hideTitle: true
---
<div className="flex items-start gap-6 not-prose" id="introduction">
<img src="/docs/img/icons/menu/reference-swift.svg" className="w-8 h-8 rounded" />
<div className="flex flex-col gap-2">
<h1 className="text-3xl text-scale-1200 m-0">Swift Client Library</h1>
<h2 className="text-base font-mono text-scale-1100">@supabase-community/supabase-swift</h2>
</div>
</div>
<div className="max-w-xl">
This reference documents every object and method available in Supabase's Swift library, [supabase-swift](https://github.com/supabase-community/supabase-swift). You can use supabase-swift to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
We also provide a [supabase](https://pub.dev/packages/supabase) package for non-Swift projects.
</div>
<div className="max-w-xl bg-slate-300 px-4 py-2 rounded-md">
<p>The Swift client library is created and maintained by the Supabase community, and is not an official library. Please be tolerant of areas where the library is still being developed, and — as with all the libraries — feel free to contribute wherever you find issues.</p>
<p>
Huge thanks to official maintainer, [Maail](https://github.com/maail).
</p>
</div>
+12
View File
@@ -38,6 +38,10 @@ const levelsData = {
icon: '/docs/img/icons/menu/realtime',
name: 'Realtime',
},
analytics: {
icon: '/docs/img/icons/menu/analytics',
name: 'Analytics',
},
storage: {
icon: '/docs/img/icons/menu/storage',
name: 'Storage',
@@ -86,6 +90,10 @@ const levelsData = {
icon: '/docs/img/icons/menu/reference-python',
name: 'Python Reference v2.0',
},
reference_swift_v1: {
icon: '/docs/img/icons/menu/reference-swift',
name: 'Swift Reference v1.0',
},
reference_cli: {
icon: '/docs/img/icons/menu/reference-cli',
name: 'CLI Reference',
@@ -106,6 +114,10 @@ const levelsData = {
icon: '/docs/img/icons/menu/reference-realtime',
name: 'Realtime Server Reference',
},
reference_self_hosting_analytics: {
icon: '/docs/img/icons/menu/reference-analytics',
name: 'Analytics Server Reference',
},
}
const MobileHeader = memo(function MobileHeader() {
+7 -1
View File
@@ -4,6 +4,8 @@ import specStorageV0 from '~/../../spec/storage_v0_config.yaml' assert { type: '
import specRealtimeV0 from '~/../../spec/realtime_v0_config.yaml' assert { type: 'yml' }
// @ts-expect-error
import specAuthV1 from '~/../../spec/gotrue_v1_config.yaml' assert { type: 'yml' }
// @ts-expect-error
import specAnalyticsV0 from '~/../../spec/analytics_v0_config.yaml' assert { type: 'yml' }
function getStorageConfigV0() {
return { ...specStorageV0 }
@@ -17,4 +19,8 @@ function getAuthConfigV1() {
return { ...specAuthV1 }
}
export { getStorageConfigV0, getRealtimeConfigV0, getAuthConfigV1 }
function getAnalyticsConfigV0() {
return { ...specAnalyticsV0 }
}
export { getStorageConfigV0, getRealtimeConfigV0, getAuthConfigV1, getAnalyticsConfigV0 }
+4 -1
View File
@@ -35,7 +35,10 @@
"gen:supabase-js:v2": "npm-run-all gen:supabase-js:v2:ref",
"gen:supabase-js:v2:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_js_v2.yml --output ./docs/reference/javascript/generated",
"gen:realtime": "npm-run-all gen:realtime:config",
"gen:realtime:config": "ts-node ./generator/index.ts gen --type config --input ../../spec/realtime_v0_config.yaml --output ./docs/reference/realtime/generated/config.mdx"
"gen:realtime:config": "ts-node ./generator/index.ts gen --type config --input ../../spec/realtime_v0_config.yaml --output ./docs/reference/realtime/generated/config.mdx",
"gen:analytics": "npm-run-all gen:analytics:config gen:analytics:usage",
"gen:analytics:config": "ts-node ./generator/index.ts gen --type config --input ../../spec/analytics_v0_config.yaml --output ./docs/reference/analytics/generated/config.mdx",
"gen:analytics:usage": "ts-node ./generator/index.ts gen --type api --input ../../spec/transforms/analytics_v0_openapi_deparsed.json --output ./docs/reference/analytics/generated/usage.mdx"
},
"dependencies": {
"@algolia/autocomplete-js": "^1.7.2",
@@ -20,7 +20,7 @@ Supabase provides client libraries for the REST and Realtime APIs. Some librarie
| `Language` | `Source Code` | `Documentation` |
| ----------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| C# | [supabase-js](https://github.com/supabase-community/supabase-csharp) | [Docs](https://supabase.com/docs/reference/csharp/introduction) |
| C# | [supabase-csharp](https://github.com/supabase-community/supabase-csharp) | [Docs](https://supabase.com/docs/reference/csharp/introduction) |
| Go | [supabase-go](https://github.com/supabase-community/supabase-go) | |
| Kotlin | [supabase-kt](https://github.com/supabase-community/supabase-kt) | |
| Python | [supabase-py](https://github.com/supabase-community/supabase-py) | [Docs](https://supabase.com/docs/reference/python/initializing) |
@@ -1,13 +1,11 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
title: 'Enterprise SSO',
title: 'Enterprise Single Sign-On',
description: 'Learn about Single Sign-On support in Supabase Auth for enterprise applications',
}
Supabase Auth supports building enterprise applications that require Single Sign-On (SSO) authentication. At this time only [SSO with SAML 2.0](/guides/auth/sso/auth-sso-saml) is supported in an early beta.
If you are interested in using SAML 2.0 SSO with your Supabase project, please [open a new support ticket](https://app.supabase.com/support/new).
Supabase Auth supports building enterprise applications that require Single Sign-On (SSO) authentication [with SAML 2.0](/docs/guides/auth/sso/auth-sso-saml).
export const Page = ({ children }) => <Layout meta={meta} children={children} />
+125 -77
View File
@@ -2,28 +2,35 @@ import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'auth-sso-saml',
title: 'Single Sign-On with SAML 2.0',
description: 'Use Single Sign-On (SSO) authentication with SAML 2.0',
title: 'Single Sign-On with SAML 2.0 for Projects',
description: 'Use Single Sign-On (SSO) authentication on your project with SAML 2.0',
video: 'https://www.youtube.com/v/em1cpOAXknM',
}
Supabase Auth supports enterprise-level Single Sign-On (SSO) for any identity providers compatible with the using the SAML 2.0 protocol.
Supabase Auth supports enterprise-level Single Sign-On (SSO) for any identity providers compatible with the using the SAML 2.0 protocol. This is a non-exclusive list of supported identity providers:
<Admonition type="info">
This is an early beta release of these APIs. CLI and Dashboard support for SSO is under development.
- Google Workspaces (formerly known as GSuite)
- Okta, Auth0
- Microsoft Active Directory, Azure Active Directory, Microsoft Entra
- PingIdentity
- OneLogin
If you are comfortable using these APIs and would like to try out SSO with SAML 2.0 for your project, please [open a support ticket](https://app.supabase.com/support/new).
If you're having issues with identity provider software not on this list, please [open a support ticket](https://app.supabase.com/support/new).
These APIs are not expected to change before the feature is generally available, but we do reserve the right to modify them. Projects in the Beta will be notified of any changes.
## Prerequisites
</Admonition>
This guide requires the use of the [Supabase CLI](/docs/guides/cli). Please make sure you're using version v1.46.4 or higher. You can use `supabase -v` to see the currently installed version.
SAML 2.0 support is disabled by default on Supabase projects. You can configure this on the [Auth Providers](https://app.supabase.com/project/_/auth/providers) page on your project.
Please note that SAML 2.0 support is offered on tiers Pro and above. Check the [Pricing](https://supabase.com/pricing) page for more information.
## Terminology
The number of SAML and SSO acronyms can often overwhelming. Here's a glossary which you can refer back to at any time:
The number of SAML and SSO acronyms can often be overwhelming. Here's a glossary which you can refer back to at any time:
- **Identity Provider**, **IdP**, or **IDP**
This is software that manages user accounts at a company or organization. It can verify the identity of a user and exchange that information with your Supabase project. Commonly used identity providers are: Microsoft Active Directory (Azure AD, Microsoft Entra), Okta, Google Workspaces (GSuite), PingIdentity, OneLogin, and many others.
An identity provider is a service that manages user accounts at a company or organization. It can verify the identity of a user and exchange that information with your Supabase project and other applications. It acts as a single source of truth for user identities and access rights. Commonly used identity providers are: Microsoft Active Directory (Azure AD, Microsoft Entra), Okta, Google Workspaces (GSuite), PingIdentity, OneLogin, and many others. There are also self-hosted and on-prem versions of identity providers, and sometimes they are accessible only by having access to a company VPN or being in a specific building.
- **Service Provider**, **SP**
This is the software that is asking for user information from an identity provider. In Supabase, this is your project's Auth server.
- **Assertion**
@@ -47,17 +54,20 @@ The number of SAML and SSO acronyms can often overwhelming. Here's a glossary wh
Below is information about your project's SAML 2.0 configuration which you can share with the company or organization that you're trying to on-board.
| Name | Value |
| ------------ | --------------------------------------------------------- |
| EntityID | `https://<project>.supabase.co/auth/v1/sso/saml/metadata` |
| Metadata URL | `https://<project>.supabase.co/auth/v1/sso/saml/metadata` |
| ACS URL | `https://<project>.supabase.co/auth/v1/sso/saml/acs` |
| SLO URL | `https://<project>.supabase.co/auth/v1/sso/slo` |
| NameID | Required `emailAddress` or `persistent` |
| Name | Value |
| --------------------------- | ----------------------------------------------------------------------- |
| EntityID | `https://<project>.supabase.co/auth/v1/sso/saml/metadata` |
| Metadata URL | `https://<project>.supabase.co/auth/v1/sso/saml/metadata` |
| Metadata URL<br/>(download) | `https://<project>.supabase.co/auth/v1/sso/saml/metadata?download=true` |
| ACS URL | `https://<project>.supabase.co/auth/v1/sso/saml/acs` |
| SLO URL | `https://<project>.supabase.co/auth/v1/sso/slo` |
| NameID | Required `emailAddress` or `persistent` |
Note that SLO (Single Logout) is not supported at this time with Supabase Auth as it is a rarely supported feature by identity providers. However, the URL is registered and advertised for when this does become available.
Append `?download=true` to the Metadata URL to get a downloadable Metadata XML file.
Append `?download=true` to the Metadata URL to download the Metadata XML file. This is useful in cases where the identity provider requires a file.
Alternatively, you can use the `supabase sso info --project-ref <your-project>` command to get setup information for your project.
### User accounts and identities
@@ -119,18 +129,7 @@ CREATE POLICY "View organization settings."
## Managing SAML 2.0 connections
### Prerequisites
SSO support with SAML 2.0 is in an early beta release. This guide uses the following software which you need to install on your machine to configure your project:
- [**cURL**](https://curl.se)
It is typically pre-installed in macOS and GNU/Linux distributions.
- [**jq**](https://stedolan.github.io/jq/)
You can install it with `brew install jq` on macOS or using your distribution's package manager.
You would need access to two keys -- the `anon` and `service_role` key. You can obtain these on the [Project API Keys](https://app.supabase.com/project/_/settings/api) page in the dashboard.
We publish an [OpenAPI specification](https://github.com/supabase/gotrue/blob/master/openapi.yaml) which you can refer to at any time.
Once you've enabled SAML 2.0 support on your project via the [Auth Providers](https://app.supabase.com/project/_/auth/providers) page in the dashboard, you can use the [Supabase CLI](/docs/guides/cli) to add, update, remove and view information about identity providers.
### Add a connection
@@ -151,40 +150,34 @@ Commonly used SAML 2.0 Identity Providers that support Metadata URLs:
Commonly used SAML 2.0 Identity Providers that only support Metadata XML files:
- Google Workspaces (GSuite)
- Any self-hosted or on-prem identity provider behind a VPN
Once you've obtained the SAML 2.0 Metadata XML file or URL you can establish a connection with your project's Supabase Auth server by invoking this API:
Once you've obtained the SAML 2.0 Metadata XML file or URL you can establish a connection with your project's Supabase Auth server by using the [Supabase CLI](/docs/guides/cli):
```bash
curl -X POST \
-H 'Content-Type: application/json' \
-H 'apikey: <anon-jwt>' \
-H 'Authorization: Bearer <service_role-jwt>' \
--data-binary '@/tmp/body.json' \
'https://<project>.supabase.co/auth/v1/admin/sso/providers'
```
To create the `/tmp/body.json` file you can use this:
```bash
jq --null-input \
--arg metadata_url "https://..." \
'{ "type": "saml", "metadata_url": $metadata_url, "domains": ["company.com"] }' \
> /tmp/body.json
supabase sso add --type saml --project-ref <your-project> \
--metadata-url 'https://company.com/idp/saml/metadata' \
--domains company.com
```
If you wish to use a Metadata XML file instead, you can use:
```bash
jq --null-input \
-M \
--rawfile metadata_file /path/to/metadata.xml \
'{ "type": "saml", "metadata_xml": $metadata_file, "domains": ["company.com"] }' \
> /tmp/body.json
supabase sso add --type saml --project-ref <your-project> \
--metadata-file /path/to/saml/metadata.xml \
--domains company.com
```
Once you've executed the cURL command with the correct body, you should see details about the registered SAML 2.0 Identity Provider.
This command will register a new identity provider with your project's Auth server. When successful, you will see the details of the provider such as it's SAML information and registered domains.
To initiate a sign-in request from your front-end application you can use:
Please note that only persons with write access to the project can register, update or remove identity providers.
Once you've added an identity provider, users who have access to it can sign in to your application. With SAML 2.0 there are two ways that users can sign in to your project:
- By signing-in from your application's user interface, commonly known as **SP (Service Provider) Initiated Flow**
- By clicking on an icon in the application menu on the company intranet or identity provider page, commonly known as **Identity Provider Initiated (IdP) Flow**
To initiate a sign-in request from your application's user interface (i.e. the SP Initiated Flow), you can use:
```typescript
supabase.auth.signInWithSSO({
@@ -192,11 +185,11 @@ supabase.auth.signInWithSSO({
})
```
Which will start the sign-in process using the SSO Identity Provider registered for the `company.com` domain name. If the SSO Identity Provider does not have an associated domain name, you can use `providerId` instead.
Calling this method starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
### Understanding attribute mappings
When a user signs in using the SAML 2.0 Single Sign-On protocol, an XML document called the SAML Assertion is exchanged between the Identity Provider and Supabase Auth.
When a user signs in using the SAML 2.0 Single Sign-On protocol, an XML document called the SAML Assertion is exchanged between the identity provider and Supabase Auth.
This assertion contains information about the user's identity and other authentication information, such as:
@@ -206,9 +199,9 @@ This assertion contains information about the user's identity and other authenti
- Department or organization
- Other attributes present in the users directory managed by the identity provider
Other than the unique ID of the user, SAML does not make it mandatory that any other attributes appear in the assertion. Identity Providers are configured about what user information is shared with your project.
With exception of the unique user ID, SAML does not require any other attributes in the assertion. Identity providers can be configured so that only select user information is shared with your project.
Your project can be configured to recognize these attributes and map them into your project's database using a JSON structure. This process is called attribute mapping, and varies according to the configuration of the Identity Provider.
Your project can be configured to recognize these attributes and map them into your project's database using a JSON structure. This process is called attribute mapping, and varies according to the configuration of the identity provider.
For example, the following JSON structure configures attribute mapping for the `email` and `first_name` user identity properties.
@@ -225,7 +218,14 @@ For example, the following JSON structure configures attribute mapping for the `
}
```
You can include this structure in the `POST /auth/v1/admin/sso/providers` call under the `attribute_mapping` property.
When creating or updating an identity provider with the [Supabase CLI](/docs/guides/cli) you can include this JSON as a file with the `--attribute-mapping /path/to/attribute/mapping.json` flag.
For example, to change the attribute mappings to an existing provider you can use:
```bash
supabase sso update <provider-uuid> --project-ref <your-project> \
--attribute-mapping /path/to/attribute/mapping.json
```
Given a SAML 2.0 assertion that includes these attributes:
@@ -268,24 +268,26 @@ Supabase Auth does not require specifying attribute mappings if you only need ac
At this time it is not possible to have users without an email address, so SAML assertions without one will be rejected.
Most SAML 2.0 identity providers use LDAP attribute names. However, due to their variability and complexity operators of Identity Providers are able to customize both the `Name` and attribute value that is sent to Supabase Auth in an assertion. Please refer to the identity provider's documentation and contact the operator for details on what attributes are mapped for your project.
Most SAML 2.0 identity providers use Lightweight Directory Access Protocol (LDAP) attribute names. However, due to their variability and complexity operators of identity providers are able to customize both the `Name` and attribute value that is sent to Supabase Auth in an assertion. Please refer to the identity provider's documentation and contact the operator for details on what attributes are mapped for your project.
### Remove a connection
Once a connection to an identity provider is established, you can remove it by invoking the `DELETE` method on it:
Once a connection to an identity provider is established, you can remove it by running:
```bash
curl -X DELETE \
-H 'Content-Type: application/json' \
-H 'apikey: <anon-jwt>' \
-H 'Authorization: Bearer <service_role-jwt>' \
'https://<project>.supabase.co/auth/v1/admin/sso/providers/<provider-uuid>'
supabase sso remove <provider-id> --project-ref <your-project>
```
Once a connection is removed, all user accounts from that identity provider will be immediately logged out. User information will remain in the system, but it will no longer be possible for any of those accounts to be accessed in the future, even if you add the connection again.
If successful, the details of the removed identity provider will be shown. All user accounts from that identity provider will be immediately logged out. User information will remain in the system, but it will no longer be possible for any of those accounts to be accessed in the future, even if you add the connection again.
If you need to reassign those user accounts to another identity provider, please [open a support ticket](https://app.supabase.com/support/new).
A list of all registered identity providers can be displayed by running:
```bash
supabase sso list --project-ref <your-project>
```
### Update a connection
You may wish to update settings about a connection to a SAML 2.0 identity provider.
@@ -293,23 +295,69 @@ You may wish to update settings about a connection to a SAML 2.0 identity provid
Commonly this is necessary when:
- Cryptographic keys are rotated or have expired
- Metadata URL has changed, but is the same Identity Provider
- Other SAML 2.0 Metadata attributes have changed, but it is still the same Identity Provider
- Metadata URL has changed, but is the same identity provider
- Other SAML 2.0 Metadata attributes have changed, but it is still the same identity provider
- You are updating the domains or attribute mapping
```bash
curl -X PUT \
-H 'Content-Type: application/json' \
-H 'apikey: <anon-jwt>' \
-H 'Authorization: Bearer <service_role-jwt>' \
--data-binary '@/tmp/body.json' \
'https://<project>.supabase.co/auth/v1/admin/sso/providers/<provider-uuid>'
You can use the following command to update the configuration of an identity provider:
```bash
supabase sso update <provider-id> --project-ref <your-project>
```
The request body has the same structure as when you're adding a connection to an Identity Provider.
Please use `--help` to see all available flags.
It is not possible to change the Identity Provider's unique SAML identifier known as `EntityID`. Everything else can be updated. If the SAML `EntityID` of your identity provider has changed, it is regarded as a new identity provider and you will have to register it like a new connection.
It is not possible to change the unique SAML identifier of the identity provider, known as `EntityID`. Everything else can be updated. If the SAML `EntityID` of your identity provider has changed, it is regarded as a new identity provider and you will have to register it like a new connection.
### Retrieving information about a connection
You can always obtain a list of all registered providers using:
```bash
supabase sso list --project-ref <your-project>
```
This list will only include basic information about each provider. To see all of the information about a provider you can use:
```bash
supabase sso show <provider-id> --project-ref <your-project>
```
You can use the `-o json` flag to output the information as JSON, should you need to. Other formats may be supported, please use `--help` to see all available options.
## Frequently Asked Questions
### How do I publish my application to an identity provider's marketplace?
Many cloud-based identity providers offer a marketplace where you can register your application for easy on-boarding with customers. When you use Supabase Auth's SAML 2.0 support you can register your project in any one of these marketplaces.
Please refer to the relevant documentation for each cloud-based identity provider on how you can do this. Some common marketplaces are:
- [Okta Integration Network](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/)
- [Azure Active Directory App Gallery](https://learn.microsoft.com/en-us/azure/active-directory-b2c/publish-app-to-azure-ad-app-gallery)
- [Google Workspaces Pre-integrated SAML apps catalog](https://support.google.com/a/table/9217027)
### Why do some users get: SAML Assertion does not contain email address?
Identity providers do not have to send back and email address for the user, though they often do. Supabase Auth requires that an email address is present.
The following list of commonly used SAML attribute names is inspected, in order of appearance, to discover the email address in the assertion:
- `urn:oid:0.9.2342.19200300.100.1.3`
- `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
- `http://schemas.xmlsoap.org/claims/EmailAddress`
- `mail`
- `email`
Finally if there is no such attribute, it will use the SAML `NameID` value but only if the format is advertised as `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`.
Should you run into this problem, it is most likely a misconfiguration issue **on the identity provider side.** Please instruct your contact at the company to map the user's email address to one of the above listed attribute names, typically `email`.
### How do I access the private key used for SAML in my project?
At this time it is not possible to extract the RSA private key used by your project's Supabase Auth server. This is done to keep the private key as secure as possible, given that SAML does not offer an easy way to rotate keys without disrupting service. (Please use a SAML 2.0 Metadata URL whenever possible for this reason!)
If you really need access to the key, please [open a support ticket](https://app.supabase.com/support/new) and we'll try to support you as best as possible.
export const Page = ({ children }) => <Layout meta={meta} children={children} />
@@ -407,12 +407,43 @@ If your project uses Edge Functions, you can deploy these using [`functions depl
supabase functions deploy <function_name>
```
### Enabling Local Logging
Local logs rely on the Supabase Analytics Server. This can be enabled via the CLI configuration, and requires a Google Cloud project and BigQuery access.
<Admonition type="note">
The Google Cloud project must have billing enabled.
</Admonition>
Requirements:
1. Google Cloud project number (must be paid)
2. Google Cloud project ID
3. Google Cloud JWT, obtained through [Google Cloud IAM dashboard](https://console.cloud.google.com/iam-admin/iam)
Once you have these 3 items, follow these steps:
1. Update your project's `config.toml` and fill in the following:
```
[analytics]
enabled = true
gcp_project_number = "123456"
gcp_project_id = "my-project-id"
gcp_jwt_path = "supabase/gcloud.json"
```
2. Place your JWT file at the corresponding path and ensure that it is correctly named.
3. Start your local stack using `supabase start`
This will switch the logging drivers and will direct logs to the Analytics server. You will be able to view and query your logs via the Studio Logs Explorer and Logs UI.
## Limitations and considerations
The local development environment is not as feature-complete as the Supabase Platform. We're working towards parity between the hosted platform and the local environment. Here are some of the differences:
- The Functions interface is coming soon.
- Logs are not supported through the interface, but you can access them through the Docker containers.
- You cannot update your project settings in the Dashboard. This must be done using the CLI.
export const Page = ({ children }) => <Layout meta={meta} children={children} />
@@ -363,6 +363,18 @@ const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY
})
```
### Refreshed Tokens
You will need to refresh tokens on your own, but once generated, you can pass them to Realtime.
For example, if you're using the `supabase-js` `v2` client then you can pass your token like this:
```js
// Client setup
supabase.realtime.setAuth('fresh-token')
```
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -0,0 +1,38 @@
import Layout from '~/layouts/DefaultGuideLayout'
import { getAnalyticsConfigV0 } from '~/lib/mdx/getConfig'
import Param from '~/components/Params'
export const spec = getAnalyticsConfigV0()
export const meta = {
title: 'Analytics Self-hosting Config',
description: 'How to configure and deploy Supabase Analytics.',
}
<div>{spec.info.description}</div>
<div>
{spec.info.tags.map(tag => {
return (
<>
<h2 className="text-scale-1200">{tag.title}</h2>
<p className="text-scale-1000">{tag.description}</p>
<div className="not-prose">
<h5 className="text-base text-scale-1200 mb-3">Parameters</h5>
<ul>
{spec.parameters.filter(param => param.tags.includes(tag.id)).map((param) => {
return <Param name={param.title} type={param.type} description={param.description} required={param.required} />
})}
</ul>
</div>
</>
)
})}
</div>
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
+7
View File
@@ -310,6 +310,13 @@ export const apis = [
href: 'reference/self-hosting-realtime/introduction',
description: 'Self-host your own Realtime server.',
},
{
title: 'Self-Hosting Analytics',
icon: '/docs/img/icons/menu/reference-analytics',
hasLightIcon: true,
href: 'reference/self-hosting-analytics/introduction',
description: 'Self-host your own Analytics server.',
},
]
export const platform = [
@@ -0,0 +1,167 @@
import specFile from '~/../../spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
import { gen_v3, enrichedOperation } from '~/lib/refGenerator/helpers'
import { Tabs, CodeBlock } from 'ui'
import RefSubLayout from '~/layouts/ref/RefSubLayout'
export type AcceptedValue = {
id: string
name: string
type: 'string' | 'boolean' | 'object'
description?: string
}
export type Flag = {
id: string
name: string
description: string
default_value: string
accepted_values: AcceptedValue[]
}
export type ApiParameter = {
example: string
in: string
name: string
required: boolean
schema: {
type: string
example: string
}
}
// @ts-ignore
const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' })
export default function Config() {
return (
<RefSubLayout>
<div className="flex my-16">
<div className="w-full">
<div className="grid gap-16">
<h1 className="text-4xl uppercase">{generatedSpec.info.title}</h1>
<p>{generatedSpec.info.description}</p>
</div>
<div className="grid gap-32 mx-auto max-w-5xl mt-24">
{generatedSpec.operations.map((operation: any) => (
<div className="border-b pb-8">
<RefSubLayout.Section
slug={operation.id}
title={operation.summary}
id={operation.operationId}
monoFont={false}
>
<RefSubLayout.Details>
<div className="mt-4">
<code className="text-md flex gap-4 text-md text-scale-900 break-all">
<span className="uppercase whitespace-nowrap ">{operation.operation}</span>
{operation.fullPath}
</code>
</div>
{/* Path Parameters */}
{operation.parameters &&
operation.parameters.filter((parameter) => parameter.in === 'path').length >
0 && (
<div className="mt-12">
<h2 className="border-b pb-2 text-xl">Path parameters</h2>
<ul className="mt-4">
{operation.parameters &&
operation.parameters
.filter((parameter: any) => parameter.in === 'path')
.map((parameter: any) => (
<li className="mt-8 border-b pb-6">
<div>
<div className="flex gap-4 items-center">
<span className="font-bold">{parameter.name}</span>
<div className="font-mono text-xs break-all">
{parameter.required && (
<div className="text-[10px] border border-amber-700 bg-amber-300 text-amber-900 px-2 tracking-wide font-mono py-0.25 rounded-full">
REQUIRED
</div>
)}
</div>
</div>
<p className="mt-4">{parameter.description}</p>
</div>
{parameter.example && (
<div className="mt-4 flex gap-4 items-center">
<span>Example:</span>
<span className="font-mono text-xs break-all">
{parameter.example}
</span>
</div>
)}
</li>
))}
</ul>
</div>
)}
{/* Header Parameters */}
{operation.parameters &&
operation.parameters.filter((parameter) => parameter.in === 'header').length >
0 && (
<div className="mt-12">
<h2 className="border-b pb-2 text-xl">Header parameters</h2>
<ul className="mt-4">
{operation.parameters &&
operation.parameters
.filter((parameter: any) => parameter.in === 'header')
.map((parameter: any) => (
<li className="mt-8 border-b pb-6">
<div className="flex gap-4 items-center">
<span className="font-bold">{parameter.name}</span>
<span className="font-mono text-xs break-all">
{parameter.required && 'required'}
</span>
</div>
<div className="mt-4 flex gap-4 items-center">
<span>Example:</span>
<span className="font-mono text-xs break-all">
{parameter.example}
</span>
</div>
</li>
))}
</ul>
</div>
)}
</RefSubLayout.Details>
<RefSubLayout.Examples>
{operation.responseList.length > 0 && (
<>
<h2 className="text-xl">Responses</h2>
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId={
operation.responseList[0].responseCode ??
operation.responseList[0].responseCode
}
>
{operation.responseList.map((response: any) => (
<Tabs.Panel id={response.responseCode} label={response.responseCode}>
<p>{response.description}</p>
{response?.content && response?.content['application/json'] && (
<div className="mt-8">
<CodeBlock language="bash" className="relative">
{JSON.stringify(response.content['application/json'], null, 2)}
</CodeBlock>
</div>
)}
</Tabs.Panel>
))}
</Tabs>
</>
)}
</RefSubLayout.Examples>
</RefSubLayout.Section>
</div>
))}
</div>
</div>
</div>
</RefSubLayout>
)
}
@@ -0,0 +1,115 @@
import fs from 'fs'
import matter from 'gray-matter'
import components from '~/components/index'
import { MDXRemote } from 'next-mdx-remote'
import { serialize } from 'next-mdx-remote/serialize'
// @ts-expect-error
import specFile from '~/../../spec/analytics_v0_config.yaml' assert { type: 'yml' }
import { Parameter } from '~/lib/refGenerator/refTypes'
import ReactMarkdown from 'react-markdown'
// Parameters are grouped on the page by tag
const TAGS = ['general', 'database']
export default function Config(props) {
return (
<div>
<div className="flex my-16">
<div className="w-full prose">
<h1 className="text-4xl mb-16">{specFile.info.title} Configuration</h1>
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
<div>
<div>
{props.docs
.filter((doc) => doc.introPage)
.map((item) => (
<MDXRemote {...item.content} components={components} />
))}
</div>
{TAGS.map((tag) =>
specFile.parameters
.filter((param: Parameter) => param.tags[0] === tag)
.map((parameter: Parameter, index) => (
<div>
{index === 0 && <h2 className="text-xl capitalize">{tag} Settings</h2>}
<div className="mt-8">
<div>
<h2 className="text-xl font-medium text-scale-1200 font-mono">
<span className="mr-2">$</span>
{parameter.title}
</h2>
<div className="grid" id={parameter.id}>
<div className="border-b pb-8" key={parameter.id}>
<div className=" mb-16">
<p className="mb-4 scroll-mt-16 mt-0 text-scale-1100 text-base">
<ReactMarkdown>{parameter.description}</ReactMarkdown>
</p>
<div className="grid gap-2">
<div className="flex gap-2">
Required: <code>{parameter.required.toString()}</code>
</div>
<div className="flex gap-2">
Default:
<code>
{parameter.default ? parameter.default.toString() : 'None'}
</code>
</div>
</div>
</div>
{parameter.links &&
parameter.links.map((link) => (
<div>
<h3>See also:</h3>
<li>
<a href={link.link}>{link.name}</a>
</li>
</div>
))}
</div>
</div>
</div>
</div>
</div>
))
)}
</div>
</div>
</div>
</div>
)
}
export async function getServerSideProps() {
// an array of ids of the intro sections for this library
const introPages = ['analytics']
const pages = [...introPages]
// Grab custom markdown intro page files
const allMarkdownDocs = await Promise.all(
pages.map(async (x: any, i) => {
const pathName = `docs/ref/analytics/${x}.mdx`
const markdownExists = fs.existsSync(pathName)
const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
const { data, content } = matter(fileContents)
return {
id: x,
title: x,
// ...content,
meta: data,
introPage: introPages.includes(x),
content: content ? await serialize(content || '') : null,
}
})
)
return {
props: {
docs: allMarkdownDocs,
},
}
}
@@ -0,0 +1,24 @@
import analyticsSpec from '~/../../spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
import selfHostingAnalyticsCommonSections from '~/../../spec/common-self-hosting-analytics-sections.json'
import RefSectionHandler from '~/components/reference/RefSectionHandler'
import { flattenSections } from '~/lib/helpers'
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
import { gen_v3 } from '~/lib/refGenerator/helpers'
const sections = flattenSections(selfHostingAnalyticsCommonSections)
// @ts-ignore
const spec = gen_v3(analyticsSpec, 'wat', { apiUrl: 'apiv0' })
export default function JSReference(props) {
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="api" />
}
export async function getStaticProps() {
return handleRefStaticProps(sections, '/self-hosting-analytics')
}
export function getStaticPaths() {
return handleRefGetStaticPaths()
}
@@ -0,0 +1,21 @@
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
// @ts-expect-error
import spec from '~/../../spec/supabase_swift_v1.yml' assert { type: 'yml' }
import RefSectionHandler from '~/components/reference/RefSectionHandler'
import { flattenSections } from '~/lib/helpers'
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
const sections = flattenSections(clientLibsCommonSections)
export default function JSReference(props) {
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
}
export async function getStaticProps() {
return handleRefStaticProps(sections, '/swift')
}
export function getStaticPaths() {
return handleRefGetStaticPaths()
}
@@ -0,0 +1,44 @@
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
import typeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json'
// @ts-expect-error
import spec from '~/../../spec/supabase_swift_v1.yml' assert { type: 'yml' }
import RefSectionHandler from '~/components/reference/RefSectionHandler'
import { flattenSections } from '~/lib/helpers'
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
import { useRouter } from 'next/router'
import RefSEO from '~/components/reference/RefSEO'
const sections = flattenSections(clientLibsCommonSections)
export default function JSReference(props) {
const router = useRouter()
const slug = router.query.slug[0]
const filteredSection = sections.filter((section) => section.id === slug)
const pageTitle = filteredSection[0]?.title
? `${filteredSection[0]?.title} | Supabase`
: 'Supabase'
return (
<>
<RefSEO title={pageTitle} />
<RefSectionHandler
sections={filteredSection}
spec={spec}
typeSpec={typeSpec}
pageProps={props}
type="client-lib"
/>
</>
)
}
export async function getStaticProps() {
return handleRefStaticProps(sections, '/swift')
}
export function getStaticPaths() {
return handleRefGetStaticPaths()
}
@@ -0,0 +1,21 @@
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
// @ts-expect-error
import spec from '~/../../spec/supabase_swift_v1.yml' assert { type: 'yml' }
import RefSectionHandler from '~/components/reference/RefSectionHandler'
import { flattenSections } from '~/lib/helpers'
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
const sections = flattenSections(clientLibsCommonSections)
export default function JSReference(props) {
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
}
export async function getStaticProps() {
return handleRefStaticProps(sections, '/swift/v1')
}
export function getStaticPaths() {
return handleRefGetStaticPaths()
}
@@ -0,0 +1,43 @@
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
import typeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json'
// @ts-expect-error
import spec from '~/../../spec/supabase_swift_v1.yml' assert { type: 'yml' }
import RefSectionHandler from '~/components/reference/RefSectionHandler'
import { flattenSections } from '~/lib/helpers'
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
import { useRouter } from 'next/router'
import RefSEO from '~/components/reference/RefSEO'
const sections = flattenSections(clientLibsCommonSections)
export default function JSReference(props) {
const router = useRouter()
const slug = router.query.slug[0]
const filteredSection = sections.filter((section) => section.id === slug)
const pageTitle = filteredSection[0]?.title
? `${filteredSection[0]?.title} | Supabase`
: 'Supabase'
return (
<>
<RefSEO title={pageTitle} />
<RefSectionHandler
sections={filteredSection}
spec={spec}
typeSpec={typeSpec}
pageProps={props}
type="client-lib"
/>
</>
)
}
export async function getStaticProps() {
return handleRefStaticProps(sections, '/swift/v1')
}
export function getStaticPaths() {
return handleRefGetStaticPaths()
}
@@ -0,0 +1,6 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.55762 4.87402L9.07535 15.2056L10.2522 10.6476L15.0002 9.46582L4.55762 4.87402Z" fill="#92CEAC" stroke="#299764" stroke-miterlimit="10" stroke-linejoin="bevel"/>
<path d="M1.36621 1.63246L3.49715 3.82855" stroke="#299764" stroke-miterlimit="10"/>
<line x1="5.3623" y1="1.33521" x2="5.3623" y2="3.68408" stroke="#299764" stroke-miterlimit="10"/>
<line x1="3.41797" y1="5.55371" x2="1.05225" y2="5.55371" stroke="#299764" stroke-miterlimit="10"/>
</svg>

After

Width:  |  Height:  |  Size: 559 B

@@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.55762 4.52319L9.07535 14.8547L10.2522 10.2968L15.0002 9.11499L4.55762 4.52319Z" fill="#133929" stroke="#4CC38A" stroke-miterlimit="10" stroke-linejoin="bevel"/>
<path d="M1.36621 1.28163L3.49715 3.47772" stroke="#4CC38A" stroke-miterlimit="10"/>
<line x1="5.3623" y1="0.984375" x2="5.3623" y2="3.33325" stroke="#4CC38A" stroke-miterlimit="10"/>
<line x1="3.41797" y1="5.20288" x2="1.05225" y2="5.20288" stroke="#4CC38A" stroke-miterlimit="10"/>
</svg>

After

Width:  |  Height:  |  Size: 560 B

@@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.61182 4.9248H4.5627M5.50672 4.93044H12.3882M3.61182 7.36678H4.5627M5.50672 7.37242H12.3882M3.61182 9.83835H4.5627M5.50672 9.84399H12.3882M3.61182 12.3247H4.5627M5.50672 12.3304H12.3882" stroke="#4CC38A" stroke-miterlimit="10" stroke-linejoin="bevel"/>
<path d="M2 2.59912H14V14.5991H2V2.59912Z" stroke="#4CC38A" stroke-miterlimit="10" stroke-linejoin="bevel"/>
</svg>

After

Width:  |  Height:  |  Size: 476 B

@@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.61182 4.9248H4.5627M5.50672 4.93044H12.3882M3.61182 7.36678H4.5627M5.50672 7.37242H12.3882M3.61182 9.83835H4.5627M5.50672 9.84399H12.3882M3.61182 12.3247H4.5627M5.50672 12.3304H12.3882" stroke="#4CC38A" stroke-miterlimit="10" stroke-linejoin="bevel"/>
<path d="M2 2.59912H14V14.5991H2V2.59912Z" stroke="#4CC38A" stroke-miterlimit="10" stroke-linejoin="bevel"/>
</svg>

After

Width:  |  Height:  |  Size: 476 B

@@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3644 4.77374C14.3679 4.90203 14.3693 5.03012 14.3701 5.15827C14.371 5.30448 14.371 5.45074 14.371 5.59694L14.371 5.61482V10.3851L14.371 10.419C14.371 10.56 14.371 10.7008 14.3701 10.8418C14.3693 10.97 14.3679 11.098 14.3643 11.2261C14.3569 11.5053 14.3404 11.787 14.2908 12.063C14.2404 12.3433 14.1582 12.6042 14.0285 12.8589C13.9012 13.1091 13.7348 13.3379 13.5363 13.5363C13.3379 13.7349 13.109 13.9013 12.8587 14.0287C12.6042 14.1582 12.3435 14.2404 12.0633 14.2907C11.7871 14.3404 11.5055 14.357 11.2262 14.3644C11.0979 14.3678 10.9698 14.3694 10.8416 14.3701C10.7059 14.3711 10.5701 14.371 10.4344 14.371L10.3851 14.371H5.61479L5.56546 14.371C5.42967 14.371 5.294 14.3711 5.15832 14.3701C5.03009 14.3694 4.90183 14.3678 4.77379 14.3644C4.49456 14.357 4.21273 14.3404 3.93665 14.2907C3.65646 14.2404 3.39572 14.1583 3.1412 14.0287C2.89094 13.9013 2.66197 13.7349 2.46358 13.5363C2.26504 13.3379 2.09864 13.1091 1.97135 12.8589C1.84168 12.6042 1.75951 12.3433 1.70913 12.063C1.65955 11.787 1.6431 11.5053 1.63559 11.2261C1.63207 11.098 1.63059 10.9699 1.62975 10.8418C1.62888 10.7073 1.62889 10.5729 1.62891 10.4384C1.62891 10.4207 1.62891 10.4029 1.62891 10.3851V7.69203V5.61482C1.62891 5.5988 1.62891 5.58279 1.62891 5.56677C1.6289 5.43062 1.62889 5.29442 1.62975 5.15824C1.63059 5.0301 1.63207 4.90201 1.63559 4.77371C1.6431 4.49463 1.65957 4.21302 1.70913 3.93692C1.75951 3.65653 1.84168 3.39582 1.97135 3.14111C2.09864 2.89097 2.26504 2.66207 2.46358 2.46357C2.51319 2.41395 2.5647 2.36634 2.61797 2.32083C2.77779 2.18434 2.9535 2.06688 3.14118 1.97136C3.20482 1.93899 3.26884 1.90955 3.33344 1.88286C3.52726 1.80273 3.72649 1.74703 3.93659 1.70927C4.14367 1.67196 4.35399 1.6534 4.56399 1.64328C4.63399 1.63991 4.70396 1.63746 4.77377 1.63558C4.90181 1.6321 5.03007 1.63064 5.1583 1.62985C5.31041 1.62897 5.4625 1.62897 5.61477 1.62897H7.01212H10.3851C10.5372 1.62897 10.6895 1.62897 10.8417 1.62983C10.9698 1.63062 11.098 1.63208 11.2262 1.63555C11.5055 1.64311 11.7871 1.6595 12.0633 1.70925C12.3435 1.75958 12.6042 1.84184 12.8587 1.97136C13.109 2.09872 13.3379 2.2651 13.5363 2.46359C13.7348 2.66209 13.9012 2.89099 14.0285 3.14113C14.1582 3.39584 14.2405 3.65655 14.2908 3.93694C14.3404 4.21304 14.3569 4.49465 14.3644 4.77374ZM11.7247 9.49334L11.7256 9.49437C12.8204 10.8415 12.5226 12.2854 12.3825 12.013C11.8103 10.8996 10.7442 11.1838 10.2044 11.464C10.1597 11.4907 10.1139 11.5159 10.0678 11.5407C10.0653 11.5422 10.0626 11.5438 10.0598 11.5454C10.0567 11.5472 10.0535 11.549 10.0508 11.5508L10.0517 11.5495C8.92831 12.1464 7.42003 12.1906 5.9033 11.5388C4.63145 10.9922 3.58646 10.0558 2.90796 8.97051C3.25297 9.22522 3.62568 9.4494 4.02214 9.6352C5.62503 10.3859 7.23492 10.3317 8.37424 9.63447C6.75268 8.38742 5.39918 6.76342 4.36131 5.4472C4.16168 5.21114 3.98007 4.96593 3.82737 4.71129C5.07019 5.84879 7.03337 7.27717 7.73781 7.67251C6.24262 6.09283 4.92514 4.14748 4.98693 4.20977C7.34176 6.58253 9.51444 7.92402 9.51444 7.92402C9.59627 7.96914 9.6572 8.00521 9.70556 8.03698C9.75012 7.92263 9.79044 7.80497 9.82397 7.68238C10.2 6.30796 9.77677 4.73633 8.81962 3.43877C11.0038 4.7504 12.2945 7.24149 11.7657 9.34852C11.7554 9.38939 11.7436 9.42922 11.7319 9.46905C11.7295 9.47714 11.7271 9.48524 11.7247 9.49334Z" fill="url(#paint0_linear_1002_71731)"/>
<defs>
<linearGradient id="paint0_linear_1002_71731" x1="-5.10791" y1="12.7483" x2="13.6219" y2="12.7483" gradientUnits="userSpaceOnUse">
<stop stop-color="#D8FFEC" stop-opacity="0.6"/>
<stop offset="1" stop-color="#F4FFFA"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3644 4.77374C14.3679 4.90203 14.3693 5.03012 14.3701 5.15827C14.371 5.30448 14.371 5.45074 14.371 5.59694L14.371 5.61482V10.3851L14.371 10.419C14.371 10.56 14.371 10.7008 14.3701 10.8418C14.3693 10.97 14.3679 11.098 14.3643 11.2261C14.3569 11.5053 14.3404 11.787 14.2908 12.063C14.2404 12.3433 14.1582 12.6042 14.0285 12.8589C13.9012 13.1091 13.7348 13.3379 13.5363 13.5363C13.3379 13.7349 13.109 13.9013 12.8587 14.0287C12.6042 14.1582 12.3435 14.2404 12.0633 14.2907C11.7871 14.3404 11.5055 14.357 11.2262 14.3644C11.0979 14.3678 10.9698 14.3694 10.8416 14.3701C10.7059 14.3711 10.5701 14.371 10.4344 14.371L10.3851 14.371H5.61479L5.56546 14.371C5.42967 14.371 5.294 14.3711 5.15832 14.3701C5.03009 14.3694 4.90183 14.3678 4.77379 14.3644C4.49456 14.357 4.21273 14.3404 3.93665 14.2907C3.65646 14.2404 3.39572 14.1583 3.1412 14.0287C2.89094 13.9013 2.66197 13.7349 2.46358 13.5363C2.26504 13.3379 2.09864 13.1091 1.97135 12.8589C1.84168 12.6042 1.75951 12.3433 1.70913 12.063C1.65955 11.787 1.6431 11.5053 1.63559 11.2261C1.63207 11.098 1.63059 10.9699 1.62975 10.8418C1.62888 10.7073 1.62889 10.5729 1.62891 10.4384C1.62891 10.4207 1.62891 10.4029 1.62891 10.3851V7.69203V5.61482C1.62891 5.5988 1.62891 5.58279 1.62891 5.56677C1.6289 5.43062 1.62889 5.29442 1.62975 5.15824C1.63059 5.0301 1.63207 4.90201 1.63559 4.77371C1.6431 4.49463 1.65957 4.21302 1.70913 3.93692C1.75951 3.65653 1.84168 3.39582 1.97135 3.14111C2.09864 2.89097 2.26504 2.66207 2.46358 2.46357C2.51319 2.41395 2.5647 2.36634 2.61797 2.32083C2.77779 2.18434 2.9535 2.06688 3.14118 1.97136C3.20482 1.93899 3.26884 1.90955 3.33344 1.88286C3.52726 1.80273 3.72649 1.74703 3.93659 1.70927C4.14367 1.67196 4.35399 1.6534 4.56399 1.64328C4.63399 1.63991 4.70396 1.63746 4.77377 1.63558C4.90181 1.6321 5.03007 1.63064 5.1583 1.62985C5.31041 1.62897 5.4625 1.62897 5.61477 1.62897H7.01212H10.3851C10.5372 1.62897 10.6895 1.62897 10.8417 1.62983C10.9698 1.63062 11.098 1.63208 11.2262 1.63555C11.5055 1.64311 11.7871 1.6595 12.0633 1.70925C12.3435 1.75958 12.6042 1.84184 12.8587 1.97136C13.109 2.09872 13.3379 2.2651 13.5363 2.46359C13.7348 2.66209 13.9012 2.89099 14.0285 3.14113C14.1582 3.39584 14.2405 3.65655 14.2908 3.93694C14.3404 4.21304 14.3569 4.49465 14.3644 4.77374ZM11.7247 9.49334L11.7256 9.49437C12.8204 10.8415 12.5226 12.2854 12.3825 12.013C11.8103 10.8996 10.7442 11.1838 10.2044 11.464C10.1597 11.4907 10.1139 11.5159 10.0678 11.5407C10.0653 11.5422 10.0626 11.5438 10.0598 11.5454C10.0567 11.5472 10.0535 11.549 10.0508 11.5508L10.0517 11.5495C8.92831 12.1464 7.42003 12.1906 5.9033 11.5388C4.63145 10.9922 3.58646 10.0558 2.90796 8.97051C3.25297 9.22522 3.62568 9.4494 4.02214 9.6352C5.62503 10.3859 7.23492 10.3317 8.37424 9.63447C6.75268 8.38742 5.39918 6.76342 4.36131 5.4472C4.16168 5.21114 3.98007 4.96593 3.82737 4.71129C5.07019 5.84879 7.03337 7.27717 7.73781 7.67251C6.24262 6.09283 4.92514 4.14748 4.98693 4.20977C7.34176 6.58253 9.51444 7.92402 9.51444 7.92402C9.59627 7.96914 9.6572 8.00521 9.70556 8.03698C9.75012 7.92263 9.79044 7.80497 9.82397 7.68238C10.2 6.30796 9.77677 4.73633 8.81962 3.43877C11.0038 4.7504 12.2945 7.24149 11.7657 9.34852C11.7554 9.38939 11.7436 9.42922 11.7319 9.46905C11.7295 9.47714 11.7271 9.48524 11.7247 9.49334Z" fill="url(#paint0_linear_1002_71731)"/>
<defs>
<linearGradient id="paint0_linear_1002_71731" x1="-5.10791" y1="12.7483" x2="13.6219" y2="12.7483" gradientUnits="userSpaceOnUse">
<stop stop-color="#D8FFEC" stop-opacity="0.6"/>
<stop offset="1" stop-color="#F4FFFA"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3644 4.77374C14.3679 4.90203 14.3693 5.03012 14.3701 5.15827C14.371 5.30448 14.371 5.45074 14.371 5.59694L14.371 5.61482V10.3851L14.371 10.419C14.371 10.56 14.371 10.7008 14.3701 10.8418C14.3693 10.97 14.3679 11.098 14.3643 11.2261C14.3569 11.5053 14.3404 11.787 14.2908 12.063C14.2404 12.3433 14.1582 12.6042 14.0285 12.8589C13.9012 13.1091 13.7348 13.3379 13.5363 13.5363C13.3379 13.7349 13.109 13.9013 12.8587 14.0287C12.6042 14.1582 12.3435 14.2404 12.0633 14.2907C11.7871 14.3404 11.5055 14.357 11.2262 14.3644C11.0979 14.3678 10.9698 14.3694 10.8416 14.3701C10.7059 14.3711 10.5701 14.371 10.4344 14.371L10.3851 14.371H5.61479L5.56546 14.371C5.42967 14.371 5.294 14.3711 5.15832 14.3701C5.03009 14.3694 4.90183 14.3678 4.77379 14.3644C4.49456 14.357 4.21273 14.3404 3.93665 14.2907C3.65646 14.2404 3.39572 14.1583 3.1412 14.0287C2.89094 13.9013 2.66197 13.7349 2.46358 13.5363C2.26504 13.3379 2.09864 13.1091 1.97135 12.8589C1.84168 12.6042 1.75951 12.3433 1.70913 12.063C1.65955 11.787 1.6431 11.5053 1.63559 11.2261C1.63207 11.098 1.63059 10.9699 1.62975 10.8418C1.62888 10.7073 1.62889 10.5729 1.62891 10.4384C1.62891 10.4207 1.62891 10.4029 1.62891 10.3851V7.69203V5.61482C1.62891 5.5988 1.62891 5.58279 1.62891 5.56677C1.6289 5.43062 1.62889 5.29442 1.62975 5.15824C1.63059 5.0301 1.63207 4.90201 1.63559 4.77371C1.6431 4.49463 1.65957 4.21302 1.70913 3.93692C1.75951 3.65653 1.84168 3.39582 1.97135 3.14111C2.09864 2.89097 2.26504 2.66207 2.46358 2.46357C2.51319 2.41395 2.5647 2.36634 2.61797 2.32083C2.77779 2.18434 2.9535 2.06688 3.14118 1.97136C3.20482 1.93899 3.26884 1.90955 3.33344 1.88286C3.52726 1.80273 3.72649 1.74703 3.93659 1.70927C4.14367 1.67196 4.35399 1.6534 4.56399 1.64328C4.63399 1.63991 4.70396 1.63746 4.77377 1.63558C4.90181 1.6321 5.03007 1.63064 5.1583 1.62985C5.31041 1.62897 5.4625 1.62897 5.61477 1.62897H7.01212H10.3851C10.5372 1.62897 10.6895 1.62897 10.8417 1.62983C10.9698 1.63062 11.098 1.63208 11.2262 1.63555C11.5055 1.64311 11.7871 1.6595 12.0633 1.70925C12.3435 1.75958 12.6042 1.84184 12.8587 1.97136C13.109 2.09872 13.3379 2.2651 13.5363 2.46359C13.7348 2.66209 13.9012 2.89099 14.0285 3.14113C14.1582 3.39584 14.2405 3.65655 14.2908 3.93694C14.3404 4.21304 14.3569 4.49465 14.3644 4.77374ZM11.7247 9.49334L11.7256 9.49437C12.8204 10.8415 12.5226 12.2854 12.3825 12.013C11.8103 10.8996 10.7442 11.1838 10.2044 11.464C10.1597 11.4907 10.1139 11.5159 10.0678 11.5407C10.0653 11.5422 10.0626 11.5438 10.0598 11.5454C10.0567 11.5472 10.0535 11.549 10.0508 11.5508L10.0517 11.5495C8.92831 12.1464 7.42003 12.1906 5.9033 11.5388C4.63145 10.9922 3.58646 10.0558 2.90796 8.97051C3.25297 9.22522 3.62568 9.4494 4.02214 9.6352C5.62503 10.3859 7.23492 10.3317 8.37424 9.63447C6.75268 8.38742 5.39918 6.76342 4.36131 5.4472C4.16168 5.21114 3.98007 4.96593 3.82737 4.71129C5.07019 5.84879 7.03337 7.27717 7.73781 7.67251C6.24262 6.09283 4.92514 4.14748 4.98693 4.20977C7.34176 6.58253 9.51444 7.92402 9.51444 7.92402C9.59627 7.96914 9.6572 8.00521 9.70556 8.03698C9.75012 7.92263 9.79044 7.80497 9.82397 7.68238C10.2 6.30796 9.77677 4.73633 8.81962 3.43877C11.0038 4.7504 12.2945 7.24149 11.7657 9.34852C11.7554 9.38939 11.7436 9.42922 11.7319 9.46905C11.7295 9.47714 11.7271 9.48524 11.7247 9.49334Z" fill="url(#paint0_linear_1002_71731)"/>
<defs>
<linearGradient id="paint0_linear_1002_71731" x1="-5.10791" y1="12.7483" x2="13.6219" y2="12.7483" gradientUnits="userSpaceOnUse">
<stop stop-color="#D8FFEC" stop-opacity="0.6"/>
<stop offset="1" stop-color="#F4FFFA"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3644 4.77374C14.3679 4.90203 14.3693 5.03012 14.3701 5.15827C14.371 5.30448 14.371 5.45074 14.371 5.59694L14.371 5.61482V10.3851L14.371 10.419C14.371 10.56 14.371 10.7008 14.3701 10.8418C14.3693 10.97 14.3679 11.098 14.3643 11.2261C14.3569 11.5053 14.3404 11.787 14.2908 12.063C14.2404 12.3433 14.1582 12.6042 14.0285 12.8589C13.9012 13.1091 13.7348 13.3379 13.5363 13.5363C13.3379 13.7349 13.109 13.9013 12.8587 14.0287C12.6042 14.1582 12.3435 14.2404 12.0633 14.2907C11.7871 14.3404 11.5055 14.357 11.2262 14.3644C11.0979 14.3678 10.9698 14.3694 10.8416 14.3701C10.7059 14.3711 10.5701 14.371 10.4344 14.371L10.3851 14.371H5.61479L5.56546 14.371C5.42967 14.371 5.294 14.3711 5.15832 14.3701C5.03009 14.3694 4.90183 14.3678 4.77379 14.3644C4.49456 14.357 4.21273 14.3404 3.93665 14.2907C3.65646 14.2404 3.39572 14.1583 3.1412 14.0287C2.89094 13.9013 2.66197 13.7349 2.46358 13.5363C2.26504 13.3379 2.09864 13.1091 1.97135 12.8589C1.84168 12.6042 1.75951 12.3433 1.70913 12.063C1.65955 11.787 1.6431 11.5053 1.63559 11.2261C1.63207 11.098 1.63059 10.9699 1.62975 10.8418C1.62888 10.7073 1.62889 10.5729 1.62891 10.4384C1.62891 10.4207 1.62891 10.4029 1.62891 10.3851V7.69203V5.61482C1.62891 5.5988 1.62891 5.58279 1.62891 5.56677C1.6289 5.43062 1.62889 5.29442 1.62975 5.15824C1.63059 5.0301 1.63207 4.90201 1.63559 4.77371C1.6431 4.49463 1.65957 4.21302 1.70913 3.93692C1.75951 3.65653 1.84168 3.39582 1.97135 3.14111C2.09864 2.89097 2.26504 2.66207 2.46358 2.46357C2.51319 2.41395 2.5647 2.36634 2.61797 2.32083C2.77779 2.18434 2.9535 2.06688 3.14118 1.97136C3.20482 1.93899 3.26884 1.90955 3.33344 1.88286C3.52726 1.80273 3.72649 1.74703 3.93659 1.70927C4.14367 1.67196 4.35399 1.6534 4.56399 1.64328C4.63399 1.63991 4.70396 1.63746 4.77377 1.63558C4.90181 1.6321 5.03007 1.63064 5.1583 1.62985C5.31041 1.62897 5.4625 1.62897 5.61477 1.62897H7.01212H10.3851C10.5372 1.62897 10.6895 1.62897 10.8417 1.62983C10.9698 1.63062 11.098 1.63208 11.2262 1.63555C11.5055 1.64311 11.7871 1.6595 12.0633 1.70925C12.3435 1.75958 12.6042 1.84184 12.8587 1.97136C13.109 2.09872 13.3379 2.2651 13.5363 2.46359C13.7348 2.66209 13.9012 2.89099 14.0285 3.14113C14.1582 3.39584 14.2405 3.65655 14.2908 3.93694C14.3404 4.21304 14.3569 4.49465 14.3644 4.77374ZM11.7247 9.49334L11.7256 9.49437C12.8204 10.8415 12.5226 12.2854 12.3825 12.013C11.8103 10.8996 10.7442 11.1838 10.2044 11.464C10.1597 11.4907 10.1139 11.5159 10.0678 11.5407C10.0653 11.5422 10.0626 11.5438 10.0598 11.5454C10.0567 11.5472 10.0535 11.549 10.0508 11.5508L10.0517 11.5495C8.92831 12.1464 7.42003 12.1906 5.9033 11.5388C4.63145 10.9922 3.58646 10.0558 2.90796 8.97051C3.25297 9.22522 3.62568 9.4494 4.02214 9.6352C5.62503 10.3859 7.23492 10.3317 8.37424 9.63447C6.75268 8.38742 5.39918 6.76342 4.36131 5.4472C4.16168 5.21114 3.98007 4.96593 3.82737 4.71129C5.07019 5.84879 7.03337 7.27717 7.73781 7.67251C6.24262 6.09283 4.92514 4.14748 4.98693 4.20977C7.34176 6.58253 9.51444 7.92402 9.51444 7.92402C9.59627 7.96914 9.6572 8.00521 9.70556 8.03698C9.75012 7.92263 9.79044 7.80497 9.82397 7.68238C10.2 6.30796 9.77677 4.73633 8.81962 3.43877C11.0038 4.7504 12.2945 7.24149 11.7657 9.34852C11.7554 9.38939 11.7436 9.42922 11.7319 9.46905C11.7295 9.47714 11.7271 9.48524 11.7247 9.49334Z" fill="url(#paint0_linear_1002_71731)"/>
<defs>
<linearGradient id="paint0_linear_1002_71731" x1="-5.10791" y1="12.7483" x2="13.6219" y2="12.7483" gradientUnits="userSpaceOnUse">
<stop stop-color="#D8FFEC" stop-opacity="0.6"/>
<stop offset="1" stop-color="#F4FFFA"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,337 @@
---
title: Infinite scroll with Next.js, Framer Motion, and Supabase
description: Lazy load and paginate data on scroll with Next.js and a sprinkle of Framer Motion magic ✨
author: fsansalvadore
image: infinite-scroll-thumb.jpg
thumb: infinite-scroll-thumb.jpg
tags:
- tutorial
- launch-week
- Next-js
date: '2023-04-04'
toc_depth: 6
---
Every Launch Week, we strive to approach things differently as part of our Kaizen mindset. For [Launch Week 7](https://www.supabase.com/launch-week), we decided to add some twists to our popular ticket system. While we made several changes, this post will focus on one specific modification (we'll share more about the rest this week!).
Our goal was to feature all the amazing people who generated tickets on a [single page](https://supabase.com/launch-week/tickets). However, displaying them all at once could take a toll on the loading time and negatively affect the user experience. That's where lazy loading smaller subsets via infinite scrolling came in as the solution.
With infinite scrolling, users can effortlessly scroll through content while only loading the necessary data as they go. This not only enhances performance but also creates a seamless and enjoyable user experience.
In this post, we'll detail our process of implementing infinite scrolling using Next.js, Framer Motion, and Supabase.
## Step 0. Load the first batch
First things first, let's install the dependencies we'll need.
```bash
npm install @supabase/supabase-js lodash framer-motion
```
Set up the supabase-js client and fetch the first 20 tickets through `getServerSideProps` so we don't start with an empty screen.
We'll assume our table in the db is called `my_tickets_table`.
```jsx
import { useEffect, useState } from 'react'
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('supabase-url', 'supabase-key')
export default function TicketsPage({ tickets }) {
const [loadedTickets, setLoadedTickets] = useState(tickets)
return (
<div>
{loadedTickets.map((ticket, index) => (
{/* We'll get to this part later */}
))}
</div>
)
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const { data: tickets } = await supabase!
.from('my_tickets_table')
.select('*')
.order('createdAt', { ascending: false })
.limit(20)
return {
props: {
tickets,
},
}
}
```
## Step 1. Listen to the scroll
To detect if the user is scrolling we can listen to the window `scroll` event.
If you try to `console.log()` the event returned in the listener callback, you'll notice that it fires on every single pixel scrolled. We want to avoid triggering like crazy, so we'll use a [lodash debounce function](https://www.geeksforgeeks.org/lodash-_-debounce-method/) to limit how often we call this event to once every 200 milliseconds.
Here's what it looks like:
```jsx
import { useEffect } from 'react'
import { debounce } from 'lodash'
const handleScroll = () => {
// Do stuff when scrolling
}
useEffect(() => {
const handleDebouncedScroll = debounce(() => handleScroll(), 200)
window.addEventListener('scroll', handleDebouncedScroll)
return () => {
window.removeEventListener('scroll', handleDebouncedScroll)
}
}, [])
```
## Step 2. Check if the container intersects the viewport
Next, we want to check if the bottom of the tickets container intersects with the bottom of the viewport. We can use the `getBoundingClientRect` method to get the position of the container and then compare it with the height of the viewport.
```jsx
import { useRef, useState } from 'react'
// ...
const containerRef = useRef(null)
const [offset, setOffset] = useState(1)
const [isInView, setIsInView] = useState(false)
const handleScroll = (container) => {
if (containerRef.current && typeof window !== 'undefined') {
const container = containerRef.current
const { bottom } = container.getBoundingClientRect()
const { innerHeight } = window
setIsInView((prev) => bottom <= innerHeight)
}
}
useEffect(() => {
if (isInView) {
loadMoreUsers(offset)
}
}, [isInView])
return <div ref={containerRef}>{/* List of loaded tickets */}</div>
```
## Step 3. Load tickets based on the offset
Now we can load more tickets based on the current offset. We'll use the [range](https://supabase.com/docs/reference/javascript/range) method from the supabase-js library to easily work with the pagination logic.
```jsx
export default function TicketsPage() {
const PAGE_COUNT = 20
const [offset, setOffset] = useState(1)
const [isLoading, setIsLoading] = useState(false)
const [isInView, setIsInView] = useState(false)
useEffect(() => {
if (isInView) {
loadMoreTickets(offset)
}
}, [isInView])
const loadMoreTickets = async (offset: number) => {
setIsLoading(true)
// Every time we fetch, we want to increase
// the offset to load fresh tickets
setOffset((prev) => prev + 1)
const { data: newTickets } = await fetchTickets(offset, PAGE_COUNT)
// Merge new tickets with all previously loaded
setLoadedTickets((prevTickets) => [...prevTickets, ...newTickets])
setIsLoading(false)
}
const fetchTickets = async (offset, limit) => {
const from = offset * PAGE_COUNT
const to = from + PAGE_COUNT - 1
const { data } = await supabase!
.from('my_tickets_table')
.select('*')
.range(from, to)
.order('createdAt', { ascending: false })
return data
}
}
```
## Step 4. Animate the tickets
Now that we have our tickets loaded, we want to add some animation to make them pop like dominos as they appear on the screen. For this, we're going to use the [Framer Motion](https://www.framer.com/motion/) library.
We'll wrap each ticket in a motion component and add a transition effect to stagger their appearance on the screen:
```jsx
import { motion } from 'framer-motion'
// ...
{
loadedTickets.map((ticket, index) => {
// each ticket will be delayed based on it's index
// but we need to subtract the delay from all the previously loaded tickets
const recalculatedDelay = i >= PAGE_COUNT * 2 ? (i - PAGE_COUNT * (offset - 1)) / 15 : i / 15
return (
<motion.div
key={ticket.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.4,
ease: [0.25, 0.25, 0, 1],
delay: recalculatedDelay,
}}
>
{/* Actual ticket component */}
</motion.div>
)
})
}
```
With this code, each ticket will start with an opacity of 0 and a y position of 20. As it animates into view, it will fade in and move up to its final position. The delay for each ticket will be based on its index in the array, creating a nice staggered effect.
## Step 5. Stop listening when finished
Once all the tickets have been loaded, we want to stop listening to the scroll event to avoid unnecessary requests. We can do this by setting a state variable called `isLast` to true whenever the length of the response will be less than `PAGE_COUNT`:
```jsx
if (newTickets.length < PAGE_COUNT) {
setIsLast(true)
}
```
We'll use this code to conditionally remove the event listener:
```jsx
useEffect(() => {
const handleDebouncedScroll = debounce(() => !isLast && handleScroll(), 200)
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
```
Now, when the `isLast` state variable is true, the event listener will be removed and the component will stop listening to the scroll event.
## Wrap up
That's it! We hope this post enabled you to build the next awesome infinite scroll.
Here's the complete code:
```jsx
import { useEffect, useState, useRef } from 'react'
import { createClient } from '@supabase/supabase-js'
import { debounce } from 'lodash'
import { motion } from 'framer-motion'
const supabase = createClient('supabase-url', 'supabase-key')
export default function TicketsPage({ tickets }) {
const PAGE_COUNT = 20
const containerRef = useRef(null)
const [loadedTickets, setLoadedTickets] = useState(tickets)
const [offset, setOffset] = useState(1)
const [isLoading, setIsLoading] = useState(false)
const [isInView, setIsInView] = useState(false)
const handleScroll = (container) => {
if (containerRef.current && typeof window !== 'undefined') {
const container = containerRef.current
const { bottom } = container.getBoundingClientRect()
const { innerHeight } = window
setIsInView((prev) => bottom <= innerHeight)
}
}
useEffect(() => {
const handleDebouncedScroll = debounce(() => !isLast && handleScroll(), 200)
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
useEffect(() => {
if (isInView) {
loadMoreTickets(offset)
}
}, [isInView])
const loadMoreTickets = async (offset: number) => {
setIsLoading(true)
setOffset((prev) => prev + 1)
const { data: newTickets } = await fetchTickets(offset, PAGE_COUNT)
setLoadedTickets((prevTickets) => [...prevTickets, ...newTickets])
setIsLoading(false)
}
const fetchTickets = async (offset) => {
const from = offset * PAGE_COUNT
const to = from + PAGE_COUNT - 1
const { data } = await supabase!
.from('my_tickets_table')
.select('*')
.range(from, to)
.order('createdAt', { ascending: false })
return data
}
return (
<div ref={containerRef}>
{
loadedTickets.map((ticket, index) => {
const recalculatedDelay =
i >= PAGE_COUNT * 2 ? (i - PAGE_COUNT * (offset - 1)) / 15 : i / 15
return (
<motion.div
key={ticket.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.4,
ease: [0.25, 0.25, 0, 1],
delay: recalculatedDelay,
}}
>
{/* Actual ticket component */}
</motion.div>
)
})
}
</div>
)
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const { data: tickets } = await supabase!
.from('my_tickets_table')
.select('*')
.order('createdAt', { ascending: false })
.limit(20)
return {
props: {
tickets,
},
}
}
```
If you also want to feature in the endless tickets page and have a chance to win cool swag, you're invited to [generate your unique ticket](https://www.supabase.com/launch-week) until April 16th.
See you at Launch Week! 👋
@@ -0,0 +1,85 @@
import React from 'react'
import Link from 'next/link'
import Countdown from 'react-countdown'
import _announcement from '~/data/Announcement.json'
import { AnnouncementProps } from '../../Nav/Announcement'
import { useRouter } from 'next/router'
interface CountdownStepProps {
value: string | number
unit: string
}
const announcement = _announcement as AnnouncementProps
function CountdownStep({ value, unit }: CountdownStepProps) {
return (
<div className="rounded-md p-[1px] overflow-hidden bg-gradient-to-b from-[#FFFFFF50] to-[#FFFFFF00]">
<div className="py-1 px-2 rounded-md leading-4 flex items-center justify-center bg-gradient-to-b from-[#9E44EF40] to-[#DBB8BF40] backdrop-blur-md">
<span className="m-0">{value}</span>
<span>{unit}</span>
</div>
</div>
)
}
function CountdownBanner() {
const { pathname } = useRouter()
const isLaunchWeekPage = pathname === '/launch-week'
const isLaunchWeekSection = pathname.includes('launch-week')
const renderer = ({ days, hours, minutes, seconds, completed }: any) => {
if (completed) {
// Render a completed state
return (
<div className="w-full flex gap-3 md:gap-6 items-center justify-center">
<p>Supabase Launch Week 7</p>
<div>
<Link href="/launch-week">
<a className="bg-white text-xs px-1.5 md:px-2.5 py-1 rounded-full text-[#9E44EF] shadow-none hover:shadow-mg cursor-pointer">
Now live
</a>
</Link>
</div>
</div>
)
} else {
// Render countdown
return (
<div
className={[
'w-full flex gap-3 md:gap-6 items-center md:justify-center text-sm md:text-base',
isLaunchWeekSection && '!justify-center',
].join(' ')}
>
<p>
<span className="hidden md:inline">Supabase</span> Launch Week 7
</p>
<div className="flex gap-1 items-center">
<CountdownStep value={days} unit="d" /> :
<CountdownStep value={hours} unit="h" /> :
<CountdownStep value={minutes} unit="m" /> :
<CountdownStep value={seconds} unit="s" />
</div>
{!isLaunchWeekPage && (
<div className="hidden md:block">
<Link href="/launch-week">
<a className="bg-white text-xs px-1.5 md:px-2.5 py-1 rounded-full text-[#9E44EF] shadow-none hover:shadow-mg cursor-pointer">
Get your ticket
</a>
</Link>
</div>
)}
</div>
)
}
}
return (
<div className="w-full h-14 p-2 bg-gradient-to-r from-[#9E44EF] to-[#DBB8BF] bg-blue-300 flex items-center justify-center text-white">
<Countdown date={new Date(announcement.launchDate)} renderer={renderer} />
</div>
)
}
export default CountdownBanner
@@ -71,7 +71,7 @@ export default function Ticket({
/>
{username && (
<div className="w-full">
<TicketCopy username={username} />
<TicketCopy username={username} isGolden={golden} />
</div>
)}
</div>
@@ -6,16 +6,17 @@ import { IconCopy, IconCheck } from 'ui'
type Props = {
username: string
isGolden?: boolean
}
export default function TicketCopy({ username }: Props) {
export default function TicketCopy({ username, isGolden }: Props) {
const [fadeOpacity, setFadeOpacity] = useState(1)
const [scrolling, setScrolling] = useState(false)
const [copyEnabled, setCopyEnabled] = useState(false)
const [copied, setCopied] = useState(false)
const scrollRef = useRef<HTMLParagraphElement>(null)
const buttonRef = useRef<HTMLButtonElement>(null)
const url = `${SITE_URL}/tickets/${username}?lw=7`
const url = `${SITE_URL}/tickets/${username}?lw=7${isGolden ? `&golden=true` : ''}`
useEffect(() => {
if (navigator.clipboard) {
setCopyEnabled(true)
+28 -44
View File
@@ -1,26 +1,37 @@
import React, { useEffect, useState } from 'react'
import _announcement from '~/data/Announcement.json'
import { IconChevronRight, IconX } from 'ui'
import { IconX } from 'ui'
import { useRouter } from 'next/router'
import { PropsWithChildren } from 'react'
interface AnnouncementProps {
export interface AnnouncementProps {
show: boolean
text: string
cta: string
launchDate: string
link: string
badge?: string
}
const announcement = _announcement as AnnouncementProps
const Announcement = () => {
interface AnnouncementComponentProps {
show?: boolean
className?: string
}
const Announcement = ({
show = true,
className,
children,
}: PropsWithChildren<AnnouncementComponentProps>) => {
const [hidden, setHidden] = useState(true)
const router = useRouter()
const isLaunchWeekSection = router.pathname.includes('launch-week')
// override to hide announcement
if (!announcement.show) return null
if (!show || !announcement.show) return null
// construct the key for the announcement, based on the title text
const announcementKey = 'announcement_' + announcement.text.replace(/ /g, '')
@@ -42,50 +53,23 @@ const Announcement = () => {
function handleLink() {
router.push(announcement.link)
window.localStorage.setItem(announcementKey, 'hidden')
}
if (hidden) {
// Always show if on LW section
if (!isLaunchWeekSection && hidden) {
return null
} else {
return (
<div
onClick={handleLink}
className="
launch-week-gradientBg--announcement-bar
to-green-1000
hover:from-green-1000
hover:to-green-1100 relative flex
cursor-pointer flex-row
space-x-3
overflow-hidden
text-white
"
>
<div
className="
mx-auto flex items-center gap-6 justify-center p-3 text-sm font-medium lg:container
lg:px-16 xl:px-20
"
>
<span>{announcement.text}</span>
<span className="item-center flex gap-2 pr-8 sm:px-3">
{announcement.badge && (
<div className="bg-[#2E2E2E] text-white py-0.25 rounded-2xl px-3 py-1 border border-gray-1100 whitespace-nowrap">
{announcement.badge}
</div>
)}
</span>
<span className="hidden items-center space-x-2 px-3 lg:flex">
<span>{announcement.cta}</span>
</span>
</div>
<div
className="absolute right-4 flex h-full items-center opacity-50 transition-opacity hover:opacity-100"
onClick={handleClose}
>
<IconX size={16} />
</div>
<div onClick={handleLink} className={['relative w-full cursor-pointer', className].join(' ')}>
{!isLaunchWeekSection && (
<div
className="absolute right-4 flex h-full items-center opacity-50 transition-opacity hover:opacity-100"
onClick={handleClose}
>
<IconX size={16} />
</div>
)}
{children}
</div>
)
}
+5 -3
View File
@@ -17,6 +17,7 @@ import TextLink from '../TextLink'
import Image from 'next/image'
import * as supabaseLogoWordmarkDark from 'common/assets/images/supabase-logo-wordmark--dark.png'
import * as supabaseLogoWordmarkLight from 'common/assets/images/supabase-logo-wordmark--light.png'
import CountdownBanner from '../LaunchWeek/Banners/CountdownBanner'
const Nav = () => {
const { isDarkMode } = useTheme()
@@ -194,7 +195,9 @@ const Nav = () => {
return (
<>
{/* <Announcement /> */}
<Announcement>
<CountdownBanner />
</Announcement>
<div className="sticky top-0 z-50 transform" style={{ transform: 'translate3d(0,0,999px)' }}>
<div
className={[
@@ -206,7 +209,7 @@ const Nav = () => {
<nav
className={[
`border-scale-400 border-b backdrop-blur-sm transition-opacity`,
showLaunchWeekNavMode && '!opacity-100 border-[#e0d2f430]',
showLaunchWeekNavMode && '!opacity-100 !border-[#e0d2f430]',
].join(' ')}
>
{/* <div className="relative flex justify-between h-16 mx-auto lg:container lg:px-10 xl:px-0"> */}
@@ -331,7 +334,6 @@ const Nav = () => {
)}
</div>
</div>
{/* <div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0"></div> */}
</div>
{/* </div> */}
{/* Mobile Nav Menu */}
+4 -4
View File
@@ -1,7 +1,7 @@
{
"show": true,
"text": "Launch Week 6 begins December 12th",
"cta": "Don't miss a thing, get your free ticket",
"link": "https://supabase.com/launch-week",
"badge": "Get a reminder"
"text": "Supabase Launch Week 7",
"launchDate": "2023-04-10T07:00:00.000-07:00",
"link": "/launch-week",
"badge": "Get your ticket"
}
+7
View File
@@ -271,5 +271,12 @@
"position": "Open Source Contributor",
"author_url": "https://github.com/gregnr",
"author_image_url": "https://github.com/gregnr.png"
},
{
"author_id": "fsansalvadore",
"author": "Francesco Sansalvadore",
"position": "Engineering",
"author_url": "https://github.com/fsansalvadore",
"author_image_url": "https://github.com/fsansalvadore.png"
}
]
+1
View File
@@ -41,6 +41,7 @@
"parse-numeric-range": "^1.3.0",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.2",
"react-countdown": "^2.3.5",
"react-dom": "^17.0.2",
"react-ga": "^3.3.0",
"react-markdown": "^8.0.3",
+1 -1
View File
@@ -95,7 +95,7 @@ export default function TicketHome({ users }: Props) {
}}
/>
<DefaultLayout>
<div className="bg-[#1C1C1C] -mt-20">
<div className="bg-[#1C1C1C] -mt-[65px]">
<div className="relative bg-lw7 pt-20">
<div className="relative z-10">
<SectionContainer className="flex flex-col justify-around items-center !py-4 md:!py-8 gap-2 md:gap-4 !px-2 !mx-auto lg:h-[calc(80vh-65px)] min-h-[600px] lg:min-h-[650px]">
@@ -64,7 +64,7 @@ export default function UsernamePage({ user, users, ogImageUrl }: Props) {
}}
/>
<DefaultLayout>
<div className="bg-[#1C1C1C] -mt-20">
<div className="bg-[#1C1C1C] -mt-[65px]">
<div className="relative bg-lw7 pt-20">
<div className="relative z-10">
<SectionContainer className="flex flex-col justify-around items-center !py-4 md:!py-8 gap-2 md:gap-4 !px-2 !mx-auto xl:h-[calc(90vh-65px)] min-h-[600px] md:min-h-[auto] lg:min-h-[650px]">
+11 -21
View File
@@ -52,21 +52,12 @@ export default function TicketsPage({ users }: Props) {
loadMoreUsers(offset)
}, [hasLoaded])
const getPagination = (page: number = 1, size: number) => {
const limit = size ? +size : 3
const from = page ? page * limit : 0
const to = page ? from + size : size
return { from, to }
}
const loadUsers = async (offset = 0, pageCount: number) => {
const { from, to } = getPagination(offset, pageCount)
const loadUsers = async (offset: number) => {
const from = offset * PAGE_COUNT
return await supabaseAdmin!
.from('lw7_tickets_golden')
.select('*')
.range(from, to - 1)
.range(from, from + PAGE_COUNT - 1)
.order('createdAt', { ascending: false })
}
@@ -74,7 +65,7 @@ export default function TicketsPage({ users }: Props) {
if (isLast) return
setIsLoading(true)
setOffset((prev) => prev + 1)
const { data: users } = await loadUsers(offset, PAGE_COUNT)
const { data: users } = await loadUsers(offset)
setLoadedUsers((prevUsers) => [...prevUsers, ...(users as any[])])
if ((users as any[]).length < PAGE_COUNT) setIsLast(true)
setIsLoading(false)
@@ -84,8 +75,8 @@ export default function TicketsPage({ users }: Props) {
document.body.className = 'dark bg-[#1C1C1C]'
}, [])
const isBottomInView = () => {
if (ref.current && window) {
const handleScroll = () => {
if (ref.current && typeof window !== 'undefined') {
const rect = (ref.current as HTMLDivElement)?.getBoundingClientRect()
const isInView = rect.bottom <= (window.innerHeight || document.documentElement.clientHeight)
setHasLoaded((prev) => !prev && isInView)
@@ -93,13 +84,12 @@ export default function TicketsPage({ users }: Props) {
}
useEffect(() => {
window.addEventListener(
'scroll',
debounce(() => !isLast && isBottomInView(), 200)
)
const handleDebouncedScroll = debounce(() => !isLast && handleScroll(), 200)
window.addEventListener('scroll', handleDebouncedScroll)
return () => {
window.removeEventListener('scroll', isBottomInView)
window.removeEventListener('scroll', handleDebouncedScroll)
}
}, [])
@@ -119,7 +109,7 @@ export default function TicketsPage({ users }: Props) {
}}
/>
<DefaultLayout>
<div className="bg-[#1C1C1C] -mt-20">
<div className="bg-[#1C1C1C] -mt-[65px]">
<div className="relative bg-lw7 pt-20">
<div className="relative z-10">
<SectionContainer className="flex flex-col justify-around items-center !py-4 md:!py-8 gap-2 md:gap-4 !px-2 !mx-auto h-auto">
Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

@@ -5,35 +5,35 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Angelico de los Reyes at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 15 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 15 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-angelico_de_los_reyes-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/postgres-point-in-time-recovery</guid>
<title>Point in Time Recovery is now available for Pro projects</title>
<link>https://supabase.com/blog/postgres-point-in-time-recovery</link>
<description>We're making PITR available for more projects, with a new Dashboard UI that makes it simple to use.</description>
<pubDate>Thu, 15 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Thu, 15 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/continuous-postgresql-backup-walg</guid>
<title>Continuous PostgreSQL Backups using WAL-G</title>
<link>https://supabase.com/blog/continuous-postgresql-backup-walg</link>
<description>Have you ever wanted to restore your database's state to a particular moment in time? This post explains how, using WAL-G.</description>
<pubDate>Sun, 02 Aug 2020 02:02:30 +0000</pubDate>
<pubDate>Sat, 01 Aug 2020 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-templates</guid>
<title>What are PostgreSQL Templates?</title>
<link>https://supabase.com/blog/postgresql-templates</link>
<description>What are PostgreSQL templates and what are they used for?</description>
<pubDate>Thu, 09 Jul 2020 02:02:30 +0000</pubDate>
<pubDate>Wed, 08 Jul 2020 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-physical-logical-backups</guid>
<title>Physical vs Logical Backups in PostgreSQL</title>
<link>https://supabase.com/blog/postgresql-physical-logical-backups</link>
<description>What are physical and logical backups in Postgres?</description>
<pubDate>Tue, 07 Jul 2020 02:02:30 +0000</pubDate>
<pubDate>Mon, 06 Jul 2020 22:10:00 +0000</pubDate>
</item>
</channel>
+2 -2
View File
@@ -5,14 +5,14 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Ant Wilson at Supabase</description>
<language>en</language>
<lastBuildDate>Sat, 27 Feb 2021 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Fri, 26 Feb 2021 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-ant_wilson-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/cracking-postgres-interview</guid>
<title>Cracking PostgreSQL Interview Questions</title>
<link>https://supabase.com/blog/cracking-postgres-interview</link>
<description>Understand the top PostgreSQL Interview Questions</description>
<pubDate>Sat, 27 Feb 2021 03:03:30 +0000</pubDate>
<pubDate>Fri, 26 Feb 2021 23:11:00 +0000</pubDate>
</item>
</channel>
+2 -2
View File
@@ -5,14 +5,14 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Bo Lu at Supabase</description>
<language>en</language>
<lastBuildDate>Wed, 14 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Wed, 14 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-bo_lu-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</guid>
<title>Supabase Wrappers, a Postgres FDW framework written in Rust</title>
<link>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</link>
<description>A framework for building Postgres Foreign Data Wrappers which connects to Stripe, Firebase, Clickhouse, and more.</description>
<pubDate>Wed, 14 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Wed, 14 Dec 2022 23:11:00 +0000</pubDate>
</item>
</channel>
+3 -3
View File
@@ -5,21 +5,21 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Mark Burggraf at Supabase</description>
<language>en</language>
<lastBuildDate>Wed, 23 Nov 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Wed, 23 Nov 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-burggraf-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/sql-or-nosql-both-with-postgresql</guid>
<title>SQL or NoSQL? Why not use both (with PostgreSQL)?</title>
<link>https://supabase.com/blog/sql-or-nosql-both-with-postgresql</link>
<description>How to turn Postgres into an easy-to-use NoSQL database that retains all the power of SQL</description>
<pubDate>Wed, 23 Nov 2022 03:03:30 +0000</pubDate>
<pubDate>Wed, 23 Nov 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgres-wasm</guid>
<title>Postgres WASM by Snaplet and Supabase</title>
<link>https://supabase.com/blog/postgres-wasm</link>
<description>We're open sourcing postgres-wasm, a PostgresQL server that runs inside a browser, with our friends at Snaplet.</description>
<pubDate>Sun, 02 Oct 2022 02:02:30 +0000</pubDate>
<pubDate>Sun, 02 Oct 2022 22:10:00 +0000</pubDate>
</item>
</channel>
+3 -3
View File
@@ -5,21 +5,21 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Michel Pelletier at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 15 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 15 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-michel-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/vault-now-in-beta</guid>
<title>Supabase Vault is now in Beta</title>
<link>https://supabase.com/blog/vault-now-in-beta</link>
<description>A Postgres extension to store encrypted secrets and encrypt data.</description>
<pubDate>Thu, 15 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Thu, 15 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/transparent-column-encryption-with-postgres</guid>
<title>Transparent Column Encryption with Postgres</title>
<link>https://supabase.com/blog/transparent-column-encryption-with-postgres</link>
<description>Using pgsodium's Transparent Column Encryption to encrypt data and provide your users with row-level encryption.</description>
<pubDate>Wed, 30 Nov 2022 03:03:30 +0000</pubDate>
<pubDate>Wed, 30 Nov 2022 23:11:00 +0000</pubDate>
</item>
</channel>
+6 -6
View File
@@ -5,42 +5,42 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Oliver Rice at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 16 Feb 2023 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 16 Feb 2023 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-oli_rice-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/type-constraints-in-65-lines-of-sql</guid>
<title>Type Constraints in 65 lines of SQL</title>
<link>https://supabase.com/blog/type-constraints-in-65-lines-of-sql</link>
<description>Creating validated data types in Postgres</description>
<pubDate>Thu, 16 Feb 2023 03:03:30 +0000</pubDate>
<pubDate>Thu, 16 Feb 2023 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/pg-graphql-v1</guid>
<title>pg_graphql v1.0</title>
<link>https://supabase.com/blog/pg-graphql-v1</link>
<description>Announcing the v1.0 release of pg_graphql</description>
<pubDate>Thu, 15 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Thu, 15 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</guid>
<title>Supabase Wrappers, a Postgres FDW framework written in Rust</title>
<link>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</link>
<description>A framework for building Postgres Foreign Data Wrappers which connects to Stripe, Firebase, Clickhouse, and more.</description>
<pubDate>Wed, 14 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Wed, 14 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/pg-jsonschema-a-postgres-extension-for-json-validation</guid>
<title>pg_jsonschema: JSON Schema support for Postgres</title>
<link>https://supabase.com/blog/pg-jsonschema-a-postgres-extension-for-json-validation</link>
<description>Today we're releasing pg_jsonschema, a Postgres extension for JSON validation.</description>
<pubDate>Thu, 18 Aug 2022 02:02:30 +0000</pubDate>
<pubDate>Thu, 18 Aug 2022 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/audit</guid>
<title>Postgres Auditing in 150 lines of SQL</title>
<link>https://supabase.com/blog/audit</link>
<description>PostgreSQL has a robust set of features which we can leverage to create a generic auditing solution in 150 lines of SQL.</description>
<pubDate>Mon, 07 Mar 2022 03:03:30 +0000</pubDate>
<pubDate>Mon, 07 Mar 2022 23:11:00 +0000</pubDate>
</item>
</channel>
@@ -5,42 +5,42 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Paul Copplestone at Supabase</description>
<language>en</language>
<lastBuildDate>Wed, 14 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Wed, 14 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-paul_copplestone-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</guid>
<title>Supabase Wrappers, a Postgres FDW framework written in Rust</title>
<link>https://supabase.com/blog/postgres-foreign-data-wrappers-rust</link>
<description>A framework for building Postgres Foreign Data Wrappers which connects to Stripe, Firebase, Clickhouse, and more.</description>
<pubDate>Wed, 14 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Wed, 14 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgres-crdt</guid>
<title>pg_crdt - an experimental CRDT extension for Postgres</title>
<link>https://supabase.com/blog/postgres-crdt</link>
<description>Embedding Yjs and Automerge into Postgres for collaborative applications.</description>
<pubDate>Fri, 09 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Fri, 09 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/partial-postgresql-data-dumps-with-rls</guid>
<title>Partial data dumps using Postgres Row Level Security</title>
<link>https://supabase.com/blog/partial-postgresql-data-dumps-with-rls</link>
<description>Using RLS to create seed files for local PostgreSQL testing.</description>
<pubDate>Mon, 27 Jun 2022 02:02:30 +0000</pubDate>
<pubDate>Mon, 27 Jun 2022 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgres-as-a-cron-server</guid>
<title>Postgres as a CRON Server</title>
<link>https://supabase.com/blog/postgres-as-a-cron-server</link>
<description>Running repetitive tasks with your Postgres database.</description>
<pubDate>Fri, 05 Mar 2021 03:03:30 +0000</pubDate>
<pubDate>Thu, 04 Mar 2021 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-views</guid>
<title>Postgres Views</title>
<link>https://supabase.com/blog/postgresql-views</link>
<description>Creating and using a view in PostgreSQL.</description>
<pubDate>Wed, 18 Nov 2020 03:03:30 +0000</pubDate>
<pubDate>Tue, 17 Nov 2020 23:11:00 +0000</pubDate>
</item>
</channel>
+3 -3
View File
@@ -5,21 +5,21 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Pavel Borisov at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 15 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 15 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-pavel-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/new-in-postgres-15</guid>
<title>What's new in Postgres 15?</title>
<link>https://supabase.com/blog/new-in-postgres-15</link>
<description>Describes the release of Postgres 15, new features and reasons to use it</description>
<pubDate>Thu, 15 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Thu, 15 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/postgresql-commitfest</guid>
<title>What is PostgreSQL commitfest and how to contribute</title>
<link>https://supabase.com/blog/postgresql-commitfest</link>
<description>A time-tested method for contributing to the core Postgres code</description>
<pubDate>Wed, 26 Oct 2022 02:02:30 +0000</pubDate>
<pubDate>Wed, 26 Oct 2022 22:10:00 +0000</pubDate>
</item>
</channel>
@@ -5,21 +5,21 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Steve Chavez at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 15 Dec 2022 03:03:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 15 Dec 2022 23:11:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-steve_chavez-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/postgrest-11-prerelease</guid>
<title>PostgREST 11 pre-release</title>
<link>https://supabase.com/blog/postgrest-11-prerelease</link>
<description>Describes new features of PostgREST 11 pre-release</description>
<pubDate>Thu, 15 Dec 2022 03:03:30 +0000</pubDate>
<pubDate>Thu, 15 Dec 2022 23:11:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/roles-postgres-hooks</guid>
<title>Protecting reserved roles with PostgreSQL Hooks</title>
<link>https://supabase.com/blog/roles-postgres-hooks</link>
<description>Using Postgres Hooks to protect functionality in your Postgres database.</description>
<pubDate>Thu, 01 Jul 2021 02:02:30 +0000</pubDate>
<pubDate>Thu, 01 Jul 2021 22:10:00 +0000</pubDate>
</item>
</channel>
+4 -4
View File
@@ -5,28 +5,28 @@
<link>https://supabase.com/blog</link>
<description>Latest Postgres news from Victor at Supabase</description>
<language>en</language>
<lastBuildDate>Thu, 13 Oct 2022 02:02:30 +0000</lastBuildDate>
<lastBuildDate>Thu, 13 Oct 2022 22:10:00 +0000</lastBuildDate>
<atom:link href="https://supabase.com/planetpg-victor-rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid>https://supabase.com/blog/postgres-full-text-search-vs-the-rest</guid>
<title>Postgres Full Text Search vs the rest</title>
<link>https://supabase.com/blog/postgres-full-text-search-vs-the-rest</link>
<description>Comparing one of the most popular Postgres features against alternatives</description>
<pubDate>Thu, 13 Oct 2022 02:02:30 +0000</pubDate>
<pubDate>Thu, 13 Oct 2022 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/choosing-a-postgres-primary-key</guid>
<title>Choosing a Postgres Primary Key</title>
<link>https://supabase.com/blog/choosing-a-postgres-primary-key</link>
<description>Turns out the question of which identifier to use as a Primary Key is complicated -- we're going to dive into some of the complexity and inherent trade-offs, and figure things out</description>
<pubDate>Wed, 07 Sep 2022 02:02:30 +0000</pubDate>
<pubDate>Wed, 07 Sep 2022 22:10:00 +0000</pubDate>
</item>
<item>
<guid>https://supabase.com/blog/seen-by-in-postgresql</guid>
<title>Implementing "seen by" functionality with Postgres</title>
<link>https://supabase.com/blog/seen-by-in-postgresql</link>
<description>Different approaches for tracking visitor counts with PostgreSQL.</description>
<pubDate>Sun, 17 Jul 2022 02:02:30 +0000</pubDate>
<pubDate>Sun, 17 Jul 2022 22:10:00 +0000</pubDate>
</item>
</channel>
+170 -163
View File
File diff suppressed because it is too large. Load diff
+19 -6
View File
@@ -74,14 +74,27 @@ STUDIO_DEFAULT_PROJECT=Default Project
STUDIO_PORT=3000
# replace if you intend to use Studio outside of localhost
SUPABASE_PUBLIC_URL=http://localhost:8000
SUPABASE_PUBLIC_URL=http://localhost:8000
# Enable webp support
IMGPROXY_ENABLE_WEBP_DETECTION=true
# Configure Logflare API Calls
LOGFLARE_API_KEY=api-key
LOGFLARE_URL=http://localhost:54329
# Enable logging and observability in the UI
NEXT_PUBLIC_ENABLE_LOGS=true
############
# Logs - Configuration for Logflare
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
############
LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key
# Change vector.toml sinks to reflect this change
LOGFLARE_HTTP_PORT=4001
LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key
# Change vector.toml sources.docker_syslog to reflect this change
VECTOR_PORT=9000
VECTOR_API_PORT=9001
# Google Cloud Project details
GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
+153
View File
@@ -0,0 +1,153 @@
# Usage
# Start: docker compose -f docker-compose.yml -f docker-compose-logging.yml up
# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml -f docker-compose-logging.yml up
# Stop: docker compose down
# Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml -f docker-compose-logging.yml down -v --remove-orphans
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
version: "3.8"
services:
studio:
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: studio
depends_on:
analytics:
condition: service_healthy
environment:
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_URL: http://analytics:4000
NEXT_PUBLIC_ENABLE_LOGS: true
kong:
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: kong
depends_on:
analytics:
condition: service_healthy
auth:
depends_on:
analytics:
condition: service_healthy
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: auth
rest:
depends_on:
analytics:
condition: service_healthy
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: rest
realtime:
depends_on:
analytics:
condition: service_healthy
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: realtime
storage:
depends_on:
analytics:
condition: service_healthy
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: storage
meta:
depends_on:
analytics:
condition: service_healthy
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: meta
analytics:
container_name: supabase-analytics
image: supabase/logflare:1.0.1
healthcheck:
test: [ "CMD", "curl", "http://localhost:4000/health" ]
timeout: 5s
interval: 5s
retries: 10
restart: unless-stopped
depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
ports:
- ${LOGFLARE_HTTP_PORT}:4000/tcp
volumes:
- type: bind
source: ${PWD}/gcloud.json
target: /opt/app/rel/logflare/bin/gcloud.json
read_only: true
environment:
MY_POD_IP: 127.0.0.1
DB_USERNAME: supabase_admin
DB_DATABASE: ${POSTGRES_DB}
DB_HOSTNAME: ${POSTGRES_HOST}
DB_PORT: ${POSTGRES_PORT}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_SCHEMA: _analytics
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
GOOGLE_PROJECT_ID: ${GOOGLE_PROJECT_ID}
GOOGLE_PROJECT_NUMBER: ${GOOGLE_PROJECT_NUMBER}
LOGFLARE_SINGLE_TENANT: true
LOGFLARE_SUPABASE_MODE: true
LOGFLARE_MIN_CLUSTER_SIZE: 1
vector:
container_name: supabase-vector
image: timberio/vector:0.28.1-alpine
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:${VECTOR_API_PORT}/health"
]
timeout: 5s
interval: 5s
retries: 3
ports:
- ${VECTOR_PORT}:${VECTOR_PORT}
- ${VECTOR_API_PORT}:${VECTOR_API_PORT}
volumes:
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro
command: [ "--config", "etc/vector/vector.yml" ]
# Comment out everything below this point if you are using an external Postgres database
db:
logging:
driver: syslog
options:
syslog-address: "tcp://localhost:${VECTOR_PORT}"
tag: db
depends_on:
vector:
# Disable this if you are using an external Postgres database
condition: service_healthy
volumes:
- ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z
+45 -10
View File
@@ -9,10 +9,16 @@ version: "3.8"
services:
studio:
container_name: supabase-studio
image: supabase/studio:20230216-e731b77
image: supabase/studio:20230330-99fed3d
restart: unless-stopped
healthcheck:
test: [ "CMD", "node", "-e", "require('http').get('http://localhost:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" ]
test:
[
"CMD",
"node",
"-e",
"require('http').get('http://localhost:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"
]
timeout: 5s
interval: 5s
retries: 3
@@ -53,10 +59,19 @@ services:
container_name: supabase-auth
image: supabase/gotrue:v2.47.0
depends_on:
db: # Disable this if you are using an external Postgres database
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
healthcheck:
test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9999/health" ]
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:9999/health"
]
timeout: 5s
interval: 5s
retries: 3
@@ -102,7 +117,8 @@ services:
container_name: supabase-rest
image: postgrest/postgrest:v10.1.2
depends_on:
db: # Disable this if you are using an external Postgres database
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
restart: unless-stopped
environment:
@@ -116,10 +132,17 @@ services:
container_name: realtime-dev.supabase-realtime
image: supabase/realtime:v2.5.1
depends_on:
db: # Disable this if you are using an external Postgres database
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
healthcheck:
test: [ "CMD", "bash", "-c", "printf \\0 > /dev/tcp/localhost/4000" ]
test:
[
"CMD",
"bash",
"-c",
"printf \\0 > /dev/tcp/localhost/4000"
]
timeout: 5s
interval: 5s
retries: 3
@@ -147,14 +170,23 @@ services:
container_name: supabase-storage
image: supabase/storage-api:v0.28.2
depends_on:
db: # Disable this if you are using an external Postgres database
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
healthcheck:
test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5000/status" ]
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:5000/status"
]
timeout: 5s
interval: 5s
retries: 3
@@ -197,7 +229,8 @@ services:
container_name: supabase-meta
image: supabase/postgres-meta:v0.60.7
depends_on:
db: # Disable this if you are using an external Postgres database
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
restart: unless-stopped
environment:
@@ -243,3 +276,5 @@ services:
- ./volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:Z
# PGDATA directory is persisted between restarts
- ./volumes/db/data:/var/lib/postgresql/data:Z
# If you want to use logging, please run with `docker compose -f docker-compose.yml -f docker-compose-logging.yml up`
+17 -9
View File
@@ -1,4 +1,4 @@
_format_version: "1.1"
_format_version: '1.1'
###
### Consumers / Users
@@ -55,7 +55,7 @@ services:
## Secure Auth routes
- name: auth-v1
_comment: "GoTrue: /auth/v1/* -> http://auth:9999/*"
_comment: 'GoTrue: /auth/v1/* -> http://auth:9999/*'
url: http://auth:9999/
routes:
- name: auth-v1-all
@@ -76,7 +76,7 @@ services:
## Secure REST routes
- name: rest-v1
_comment: "PostgREST: /rest/v1/* -> http://rest:3000/*"
_comment: 'PostgREST: /rest/v1/* -> http://rest:3000/*'
url: http://rest:3000/
routes:
- name: rest-v1-all
@@ -97,7 +97,7 @@ services:
## Secure GraphQL routes
- name: graphql-v1
_comment: "PostgREST: /graphql/v1/* -> http://rest:3000/rpc/graphql"
_comment: 'PostgREST: /graphql/v1/* -> http://rest:3000/rpc/graphql'
url: http://rest:3000/rpc/graphql
routes:
- name: graphql-v1-all
@@ -111,7 +111,7 @@ services:
hide_credentials: true
- name: request-transformer
config:
add:
add:
headers:
- Content-Profile:graphql_public
- name: acl
@@ -123,7 +123,7 @@ services:
## Secure Realtime routes
- name: realtime-v1
_comment: "Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*"
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
url: http://realtime-dev.supabase-realtime:4000/socket/
routes:
- name: realtime-v1-all
@@ -144,7 +144,7 @@ services:
## Storage routes: the storage server manages its own auth
- name: storage-v1
_comment: "Storage: /storage/v1/* -> http://storage:5000/*"
_comment: 'Storage: /storage/v1/* -> http://storage:5000/*'
url: http://storage:5000/
routes:
- name: storage-v1-all
@@ -153,10 +153,18 @@ services:
- /storage/v1/
plugins:
- name: cors
## Analytics routes
- name: analytics-v1
_comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
url: http://analytics:4000/
routes:
- name: analytics-v1-all
strip_path: true
paths:
- /analytics/v1/
## Secure Database routes
- name: meta
_comment: "pg-meta: /pg/* -> http://pg-meta:8080/*"
_comment: 'pg-meta: /pg/* -> http://pg-meta:8080/*'
url: http://meta:8080/
routes:
- name: meta-all
+4
View File
@@ -0,0 +1,4 @@
\set pguser `echo "$POSTGRES_USER"`
create schema if not exists _analytics;
alter schema _analytics owner to :pguser;
+201
View File
@@ -0,0 +1,201 @@
api:
enabled: true
address: '0.0.0.0:9001'
sources:
docker_syslog:
type: 'syslog'
address: '0.0.0.0:9000'
mode: 'tcp'
path: '/tmp/socket'
transforms:
project_logs:
type: remap
inputs:
- docker_syslog
source: |-
.project = "default"
.event_message = del(.message)
del(.procid)
del(.source_id)
del(.source_type)
del(.facility)
del(.host)
del(.id)
router:
type: route
inputs:
- project_logs
route:
kong: '.appname == "kong"'
auth: '.appname == "auth"'
rest: '.appname == "rest"'
realtime: '.appname == "realtime"'
storage: '.appname == "storage"'
db: '.appname == "db"'
# Kong logs only include api requests
kong_logs:
type: remap
inputs:
- router.kong
source: |-
req, err = parse_nginx_log(.event_message, "combined")
if err == null {
.timestamp = req.timestamp
.metadata.request.headers.referer = req.referer
.metadata.request.headers.user_agent = req.agent
.metadata.request.headers.cf_connecting_ip = req.client
.metadata.request.method = req.method
.metadata.request.path = req.path
.metadata.request.protocol = req.protocol
.metadata.response.status_code = req.status
}
# TODO: create a separate page and filter for kong error logs
kong_err:
type: remap
inputs:
- router.kong
source: |-
.metadata.request.method = "GET"
.metadata.response.status_code = 200
parsed, err = parse_nginx_log(.event_message, "error")
if err == null {
.timestamp = parsed.timestamp
.severity = parsed.severity
.metadata.request.host = parsed.host
.metadata.request.headers.cf_connecting_ip = parsed.client
url, err = split(parsed.request, " ")
if err == null {
.metadata.request.method = url[0]
.metadata.request.path = url[1]
.metadata.request.protocol = url[2]
}
}
# Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency.
auth_logs:
type: remap
inputs:
- router.auth
source: |-
parsed, err = parse_json(.event_message)
if err == null {
.metadata.timestamp = parsed.time
.metadata = merge!(.metadata, parsed)
}
# PostgREST logs are structured so we separate timestamp from message using regex
rest_logs:
type: remap
inputs:
- router.rest
source: |-
parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$')
if err == null {
.event_message = parsed.msg
.timestamp = to_timestamp!(parsed.time)
.metadata.host = .project
}
# Realtime logs are structured so we parse the severity level using regex (ignore time because it has no date)
realtime_logs:
type: remap
inputs:
- router.realtime
source: |-
.metadata.project = del(.project)
.metadata.external_id = .metadata.project
parsed, err = parse_regex(.event_message, r'^(?P<time>\d+:\d+:\d+\.\d+) \[(?P<level>\w+)\] (?P<msg>.*)$')
if err == null {
.event_message = parsed.msg
.metadata.level = parsed.level
}
# Storage logs may contain json objects so we parse them for completeness
storage_logs:
type: remap
inputs:
- router.storage
source: |-
.metadata.project = del(.project)
.metadata.tenantId = .metadata.project
parsed, err = parse_json(.event_message)
if err == null {
.event_message = parsed.msg
.metadata.level = parsed.level
.metadata.timestamp = parsed.time
.metadata.context[0].host = parsed.hostname
.metadata.context[0].pid = parsed.pid
}
# Postgres logs some messages to stderr which we map to warning severity level
# TODO: parse raw postgres logs via regex
db_logs:
type: remap
inputs:
- router.db
source: |-
.metadata.host = "db-default"
.metadata.parsed.timestamp = .timestamp
.metadata.parsed.error_severity = replace!(.severity, r'^err$', "warning")
sinks:
logflare_auth:
type: 'http'
inputs:
- auth_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod&api_key=your-super-secret-and-long-logflare-key'
logflare_realtime:
type: 'http'
inputs:
- realtime_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod&api_key=your-super-secret-and-long-logflare-key'
logflare_rest:
type: 'http'
inputs:
- rest_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod&api_key=your-super-secret-and-long-logflare-key'
logflare_db:
type: 'http'
inputs:
- db_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
# We must route the sink through kong because ingesting logs before logflare is fully initialised will
# lead to broken queries from studio. This works by the assumption that containers are started in the
# following order: vector > db > logflare > kong
uri: 'http://kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=your-super-secret-and-long-logflare-key'
logflare_storage:
type: 'http'
inputs:
- storage_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2&api_key=your-super-secret-and-long-logflare-key'
logflare_kong:
type: 'http'
inputs:
- kong_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 10
uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod&api_key=your-super-secret-and-long-logflare-key'
+47 -25
View File
@@ -682,6 +682,7 @@
"parse-numeric-range": "^1.3.0",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.2",
"react-countdown": "^2.3.5",
"react-dom": "^17.0.2",
"react-ga": "^3.3.0",
"react-markdown": "^8.0.3",
@@ -9528,9 +9529,9 @@
}
},
"node_modules/@supabase/postgres-meta": {
"version": "0.60.7",
"resolved": "https://registry.npmjs.org/@supabase/postgres-meta/-/postgres-meta-0.60.7.tgz",
"integrity": "sha512-vC5mwZ4sVAA5Hw57GSSDI7rGBY8/m8RscRHaFwfnqKgXFxKMvlfrzxnP/MwXg7EXRW1jfgvMAEkxuJNLDe1YMA==",
"version": "0.62.0",
"resolved": "https://registry.npmjs.org/@supabase/postgres-meta/-/postgres-meta-0.62.0.tgz",
"integrity": "sha512-35p2KJXq1tvzIuEa1VTEbRl5Or5qQEYFLZmG30LwdyDYGzdVtuQ03rYpQLMKAG8ueuhul+PN0WCPfvH1yq3DhA==",
"dev": true,
"dependencies": {
"@sinclair/typebox": "^0.25.1",
@@ -9539,7 +9540,7 @@
"pgsql-parser": "^13.3.0",
"postgres-array": "^3.0.1",
"prettier": "^2.6.0",
"prettier-plugin-sql": "^0.12.1"
"prettier-plugin-sql": "^0.13.0"
},
"engines": {
"node": ">=16",
@@ -30868,13 +30869,13 @@
}
},
"node_modules/prettier-plugin-sql": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.12.1.tgz",
"integrity": "sha512-2z0pMmQEC61Xywerw2FJFpEIaA9lJUjB5mj+9dfRU8HkU7iICFrIizpMjSSDMoGkhh5W+IRROVgLlgRdpphI7g==",
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.13.0.tgz",
"integrity": "sha512-Ui9603tDD6PFyr7JvIEoE6cIFMQnJVDriG+oLyVThsGo/MIl5ek18JhH3xtox9ux8jvyww/FUFrJzxpZ7FIdvw==",
"dev": true,
"dependencies": {
"node-sql-parser": "^4.4.0",
"sql-formatter": "^10.0.0",
"sql-formatter": "^11.0.2",
"tslib": "^2.4.0"
},
"engines": {
@@ -31443,6 +31444,18 @@
"react": "^15.3.0 || 16 || 17 || 18"
}
},
"node_modules/react-countdown": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.5.tgz",
"integrity": "sha512-K26ENYEesMfPxhRRtm1r+Pf70SErrvW3g4CArLi/x6MPFjgfDFYePT4UghEj8p2nI0cqVV7/JjDgjyr//U60Og==",
"dependencies": {
"prop-types": "^15.7.2"
},
"peerDependencies": {
"react": ">= 15",
"react-dom": ">= 15"
}
},
"node_modules/react-csv": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
@@ -34450,16 +34463,16 @@
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
},
"node_modules/sql-formatter": {
"version": "10.7.2",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-10.7.2.tgz",
"integrity": "sha512-YspJXMr2rKMGZY50zYRBs2nCtEO/AKDrmQOxmV2CrGEOFSXUhY3YbsOUe6lX0T/7xbBs4pAYv4UObmwf78vtKg==",
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-11.0.2.tgz",
"integrity": "sha512-6QumAdGHEnI5dXEq1d0aBRP876AyA9Wp/UE7wopKNA2Mp9sKGRKVqGgoWHk4dr0J0nceesC85Y0p36qmGoNqhw==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1",
"nearley": "^2.20.1"
},
"bin": {
"sql-formatter": "bin/sql-formatter-cli.js"
"sql-formatter": "bin/sql-formatter-cli.cjs"
}
},
"node_modules/sql-parser-cst": {
@@ -39081,7 +39094,7 @@
"@storybook/addon-links": "^6.4.19",
"@storybook/react": "^6.4.19",
"@storybook/testing-library": "^0.0.9",
"@supabase/postgres-meta": "^0.60.7",
"@supabase/postgres-meta": "^0.62.0",
"@tailwindcss/typography": "^0.5.2",
"@testing-library/dom": "^8.19.0",
"@testing-library/react": "^12.1.5",
@@ -45914,9 +45927,9 @@
}
},
"@supabase/postgres-meta": {
"version": "0.60.7",
"resolved": "https://registry.npmjs.org/@supabase/postgres-meta/-/postgres-meta-0.60.7.tgz",
"integrity": "sha512-vC5mwZ4sVAA5Hw57GSSDI7rGBY8/m8RscRHaFwfnqKgXFxKMvlfrzxnP/MwXg7EXRW1jfgvMAEkxuJNLDe1YMA==",
"version": "0.62.0",
"resolved": "https://registry.npmjs.org/@supabase/postgres-meta/-/postgres-meta-0.62.0.tgz",
"integrity": "sha512-35p2KJXq1tvzIuEa1VTEbRl5Or5qQEYFLZmG30LwdyDYGzdVtuQ03rYpQLMKAG8ueuhul+PN0WCPfvH1yq3DhA==",
"dev": true,
"requires": {
"@sinclair/typebox": "^0.25.1",
@@ -45925,7 +45938,7 @@
"pgsql-parser": "^13.3.0",
"postgres-array": "^3.0.1",
"prettier": "^2.6.0",
"prettier-plugin-sql": "^0.12.1"
"prettier-plugin-sql": "^0.13.0"
}
},
"@supabase/postgrest-js": {
@@ -62800,13 +62813,13 @@
"dev": true
},
"prettier-plugin-sql": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.12.1.tgz",
"integrity": "sha512-2z0pMmQEC61Xywerw2FJFpEIaA9lJUjB5mj+9dfRU8HkU7iICFrIizpMjSSDMoGkhh5W+IRROVgLlgRdpphI7g==",
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.13.0.tgz",
"integrity": "sha512-Ui9603tDD6PFyr7JvIEoE6cIFMQnJVDriG+oLyVThsGo/MIl5ek18JhH3xtox9ux8jvyww/FUFrJzxpZ7FIdvw==",
"dev": true,
"requires": {
"node-sql-parser": "^4.4.0",
"sql-formatter": "^10.0.0",
"sql-formatter": "^11.0.2",
"tslib": "^2.4.0"
}
},
@@ -63238,6 +63251,14 @@
"prop-types": "^15.8.1"
}
},
"react-countdown": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.5.tgz",
"integrity": "sha512-K26ENYEesMfPxhRRtm1r+Pf70SErrvW3g4CArLi/x6MPFjgfDFYePT4UghEj8p2nI0cqVV7/JjDgjyr//U60Og==",
"requires": {
"prop-types": "^15.7.2"
}
},
"react-csv": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
@@ -65525,9 +65546,9 @@
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
},
"sql-formatter": {
"version": "10.7.2",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-10.7.2.tgz",
"integrity": "sha512-YspJXMr2rKMGZY50zYRBs2nCtEO/AKDrmQOxmV2CrGEOFSXUhY3YbsOUe6lX0T/7xbBs4pAYv4UObmwf78vtKg==",
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-11.0.2.tgz",
"integrity": "sha512-6QumAdGHEnI5dXEq1d0aBRP876AyA9Wp/UE7wopKNA2Mp9sKGRKVqGgoWHk4dr0J0nceesC85Y0p36qmGoNqhw==",
"dev": true,
"requires": {
"argparse": "^2.0.1",
@@ -65973,7 +65994,7 @@
"@storybook/testing-library": "^0.0.9",
"@stripe/react-stripe-js": "^1.7.0",
"@stripe/stripe-js": "^1.25.0",
"@supabase/postgres-meta": "^0.60.7",
"@supabase/postgres-meta": "^0.62.0",
"@supabase/react-data-grid": "^7.1.0-beta.7",
"@supabase/shared-types": "^0.1.40",
"@supabase/supabase-js": "^2.13.0",
@@ -69302,6 +69323,7 @@
"postcss-preset-env": "^6.7.0",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.2",
"react-countdown": "^2.3.5",
"react-dom": "^17.0.2",
"react-ga": "^3.3.0",
"react-markdown": "^8.0.3",
@@ -105,6 +105,9 @@ function useKeyboardEvents({
case 'k':
case '/':
if (event.metaKey || event.ctrlKey) {
// Some browsers (ie. firefox) will focus the address bar by default
event.preventDefault()
setIsOpen(true)
}
return
+1 -1
View File
@@ -128,7 +128,7 @@ function Toggle({
type="button"
id={id}
name={name}
className={clsx(toggleClasses, disabled && 'opacity-50 cursor-default')}
className={clsx(...toggleClasses, disabled && 'opacity-50 cursor-default')}
onClick={onClick}
disabled={disabled}
onBlur={handleBlurEvent}
+8 -8
View File
@@ -353,7 +353,7 @@ export default {
hover:text-scale-1200
`,
active: `
text-scale-1200
!text-scale-1200
border-b-2 border-scale-1200
`,
},
@@ -1061,8 +1061,8 @@ export default {
hover:bg-scale-700
`,
active: `
bg-brand-900
hover:bg-brand-900
!bg-brand-900
!hover:bg-brand-900
`,
handle_container: {
tiny: 'h-4 w-7',
@@ -1081,11 +1081,11 @@ export default {
transition
ease-in-out duration-200
`,
tiny: 'h-3 w-3',
small: 'h-5 w-5',
medium: 'h-5 w-5',
large: 'h-6 w-6',
xlarge: 'h-6 w-6',
tiny: '!h-3 !w-3',
small: '!h-5 !w-5',
medium: '!h-5 !w-5',
large: '!h-6 !w-6',
xlarge: '!h-6 !w-6',
},
handle_active: {
tiny: ' translate-x-3 dark:bg-white',
+14 -1
View File
@@ -51,10 +51,13 @@ download.tsdoc.v2:
curl -sS https://supabase.github.io/storage-js/v2/spec.json > $(REPO_DIR)/enrichments/tsdoc_v2/storage.json
curl -sS https://supabase.github.io/functions-js/v2/spec.json > $(REPO_DIR)/enrichments/tsdoc_v2/functions.json
download.analytics.v0:
curl -sS https://logflare.app/api/openapi > $(REPO_DIR)/analytics_v0_openapi.json
###############################################################################
# Transform docs into working files
###############################################################################
transform: dereference.api.v0 dereference.auth.v1 dereference.storage.v0 dereference.tsdoc.v2 combine.tsdoc.v2
transform: dereference.api.v0 dereference.auth.v1 dereference.storage.v0 dereference.tsdoc.v2 combine.tsdoc.v2
dereference.api.v0:
npx swagger-cli bundle --dereference --outfile $(REPO_DIR)/transforms/api_v0_openapi_deparsed.json $(REPO_DIR)/api_v0_openapi.json
@@ -65,6 +68,9 @@ dereference.auth.v1:
dereference.storage.v0:
npx swagger-cli bundle --dereference --outfile $(REPO_DIR)/transforms/storage_v0_openapi_deparsed.json $(REPO_DIR)/storage_v0_openapi.json
dereference.analytics.v0:
npx swagger-cli bundle --dereference --outfile $(REPO_DIR)/transforms/analytics_v0_openapi_deparsed.json $(REPO_DIR)/analytics_v0_openapi.json
# No longer updated
# dereference.tsdoc.v1:
# cd $(REPO_DIR)/parser && npm run tsdoc:dereference:functions:v1
@@ -113,6 +119,13 @@ combine-raw.tsdoc.v2:
$(REPO_DIR)/enrichments/tsdoc_v2/functions.json \
> $(REPO_DIR)/enrichments/tsdoc_v2/combined_raw.json
###############################################################################
# Validate OpenAPI 3.0
###############################################################################
validate.analytics.v0:
npx swagger-cli validate --no-schema $(REPO_DIR)/analytics_v0_openapi.json
###############################################################################
# Format everything - easier for git to track changes.
###############################################################################
+73
View File
@@ -0,0 +1,73 @@
configspec: '001'
# This section outlines the general information for the tool.
info:
id: 'analytics' # {string} A unique ID for this tool.
version: 'next' # {string} The current version number of the tool.
title: 'Analytics' # {string} A readable name.
source: 'https://github.com/supabase/realtime' # {string} Where developers can find the source code.
bugs: 'https://github.com/supabase/realtime/issues' # {string} Where developers can file bugs.
spec: 'https://github.com/supabase/supabase/blob/master/spec/realtime_v0_config.yml' # {string} Where developers can find this spec (to link directly in the docs).
description: |
You can use environment variables to configure your Analytics Server.
tags:
- id: general
title: General Settings
description: General server settings.
# This section is an array of public functions which a user might need to execute.
parameters:
- id: 'LOGFLARE_SINGLE_TENANT' # {string} A unique identifier for this param.
title: 'LOGFLARE_SINGLE_TENANT' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: 'true'
type: 'boolean'
description: |
This is will seed a singular user into the database, and will disable browser authentication. All browser usage will default to this user. Inviting team users and other team-related functionality is currently not supported for self-hosted. Logflare self-hosted is currently intended for single-user experience only.
- id: 'LOGFLARE_API_KEY' # {string} A unique identifier for this param.
title: 'LOGFLARE_API_KEY' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: ''
type: 'string'
description: |
Allows you to pass in an API key that will used for authentication. This is intended for programmatic usage where an external program sets the API key. It is advised to use the UI to configure the access tokens instead. If this value is not provided, the default API key will be automatically generated.
- id: 'LOGFLARE_SUPABASE_MODE' # {string} A unique identifier for this param.
title: 'LOGFLARE_SUPABASE_MODE' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: 'false'
type: 'boolean'
description: |
This is a special mode for Logflare which will seed additional resources for usage with Supabase self-hosted.
- id: 'PHX_HTTP_PORT' # {string} A unique identifier for this param.
title: 'PHX_HTTP_PORT' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: '4000'
type: 'string'
description: |
Port which serves HTTP requests
- id: 'DB_SCHEMA' # {string} A unique identifier for this param.
title: 'DB_SCHEMA' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: ''
type: 'string'
description: |
This ENV variable sets the search path to a custom database schema. This allows you to customize the schema used on the database.
- id: 'LOGFLARE_LOG_LEVEL' # {string} A unique identifier for this param.
title: 'LOGFLARE_LOG_LEVEL' # {string} Any name.
tags: ['general'] # {string[]} These tags are useful for grouping parameters
links: [] # {string[]} These tags are useful for grouping parameters
required: true
default: 'info'
type: 'string'
description: |
Allows the setting of the log level at runtime. For production settings, we advise `warn`.
File diff suppressed because it is too large. Load diff
+550 -11
View File
@@ -34,6 +34,12 @@
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/ProjectResponse" } }
}
},
"201": {
"description": "",
"content": {
@@ -1048,6 +1054,301 @@
"tags": ["vanity subdomain (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/upgrade": {
"post": {
"operationId": "upgradeProject",
"summary": "Upgrades the project's Postgres version",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/UpgradeDatabaseBody" } }
}
},
"responses": {
"201": { "description": "" },
"403": { "description": "" },
"500": { "description": "Failed to initiate project upgrade" }
},
"tags": ["database version upgrade (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/upgrade/eligibility": {
"get": {
"operationId": "upgradeEligibilityInformation",
"summary": "Returns the project's eligibility for upgrades",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ProjectUpgradeEligibilityResponse" }
}
}
},
"403": { "description": "" },
"500": { "description": "Failed to determine project upgrade eligibility" }
},
"tags": ["database version upgrade (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/upgrade/status": {
"get": {
"operationId": "getUpgradeStatus",
"summary": "Gets the latest status of the project's upgrade",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/DatabaseUpgradeStatusResponse" }
}
}
},
"403": { "description": "" },
"500": { "description": "Failed to retrieve project upgrade status" }
},
"tags": ["database version upgrade (beta)"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/readonly": {
"get": {
"operationId": "getReadOnlyModeStatus",
"summary": "Returns project's readonly mode status",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ReadOnlyStatusResponse" }
}
}
},
"500": { "description": "Failed to get project readonly mode status" }
},
"tags": ["database readonly mode"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/readonly/temporary-disable": {
"post": {
"operationId": "temporarilyDisableReadonlyMode",
"summary": "Disables project's readonly mode for the next 15 minutes",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"201": { "description": "" },
"500": { "description": "Failed to disable project's readonly mode" }
},
"tags": ["database readonly mode"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/config/auth/sso/providers": {
"post": {
"operationId": "createProviderForProject",
"summary": "Creates a new SSO provider",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/CreateProviderBody" } }
}
},
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/CreateProviderResponse" }
}
}
},
"403": { "description": "" },
"404": { "description": "SAML 2.0 support is not enabled for this project" }
},
"tags": ["sso"],
"security": [{ "bearer": [] }]
},
"get": {
"operationId": "listAllProviders",
"summary": "Lists all SSO providers",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ListProvidersResponse" }
}
}
},
"403": { "description": "" },
"404": { "description": "SAML 2.0 support is not enabled for this project" }
},
"tags": ["sso"],
"security": [{ "bearer": [] }]
}
},
"/v1/projects/{ref}/config/auth/sso/providers/{provider_id}": {
"get": {
"operationId": "getProviderById",
"summary": "Gets a SSO provider by its UUID",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
},
{ "name": "provider_id", "required": true, "in": "path", "schema": { "type": "string" } }
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/GetProviderResponse" }
}
}
},
"403": { "description": "" },
"404": {
"description": "Either SAML 2.0 was not enabled for this project, or the provider does not exist"
}
},
"tags": ["sso"],
"security": [{ "bearer": [] }]
},
"put": {
"operationId": "updateProviderById",
"summary": "Updates a SSO provider by its UUID",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
},
{ "name": "provider_id", "required": true, "in": "path", "schema": { "type": "string" } }
],
"requestBody": {
"required": true,
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/UpdateProviderBody" } }
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/UpdateProviderResponse" }
}
}
},
"403": { "description": "" },
"404": {
"description": "Either SAML 2.0 was not enabled for this project, or the provider does not exist"
}
},
"tags": ["sso"],
"security": [{ "bearer": [] }]
},
"delete": {
"operationId": "removeProviderById",
"summary": "Removes a SSO provider by its UUID",
"parameters": [
{
"name": "ref",
"required": true,
"in": "path",
"description": "Project ref",
"schema": { "minLength": 20, "maxLength": 20, "type": "string" }
},
{ "name": "provider_id", "required": true, "in": "path", "schema": { "type": "string" } }
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/DeleteProviderResponse" }
}
}
},
"403": { "description": "" },
"404": {
"description": "Either SAML 2.0 was not enabled for this project, or the provider does not exist"
}
},
"tags": ["sso"],
"security": [{ "bearer": [] }]
}
}
},
"info": { "title": "Supabase API (v1)", "description": "", "version": "1.0.0", "contact": {} },
@@ -1061,17 +1362,28 @@
"schemas": {
"DatabaseResponse": {
"type": "object",
"properties": { "host": { "type": "string" }, "version": { "type": "string" } },
"properties": {
"host": { "type": "string", "description": "Database host" },
"version": { "type": "string", "description": "Database version" }
},
"required": ["host", "version"]
},
"ProjectResponse": {
"type": "object",
"properties": {
"id": { "type": "string" },
"organization_id": { "type": "string" },
"name": { "type": "string" },
"region": { "type": "string" },
"created_at": { "type": "string" },
"id": { "type": "string", "description": "Id of your project" },
"organization_id": { "type": "string", "description": "Slug of your organization" },
"name": { "type": "string", "description": "Name of your project" },
"region": {
"type": "string",
"description": "Region of your project",
"example": "us-east-1"
},
"created_at": {
"type": "string",
"description": "Creation timestamp",
"example": "2023-03-29T16:32:59Z"
},
"database": { "$ref": "#/components/schemas/DatabaseResponse" }
},
"required": ["id", "organization_id", "name", "region", "created_at"]
@@ -1079,15 +1391,24 @@
"CreateProjectBody": {
"type": "object",
"properties": {
"db_pass": { "type": "string" },
"name": { "type": "string" },
"organization_id": { "type": "string" },
"plan": { "type": "string", "enum": ["free", "pro"] },
"db_pass": { "type": "string", "description": "Database password" },
"name": {
"type": "string",
"description": "Name of your project, should not contain dots"
},
"organization_id": { "type": "string", "description": "Slug of your organization" },
"plan": {
"type": "string",
"enum": ["free", "pro"],
"description": "Subscription plan",
"example": "free"
},
"region": {
"type": "string",
"enum": [
"us-east-1",
"us-west-1",
"us-west-2",
"ap-southeast-1",
"ap-northeast-1",
"ap-northeast-2",
@@ -1099,7 +1420,9 @@
"ca-central-1",
"ap-south-1",
"sa-east-1"
]
],
"description": "Region you want your server to reside in",
"example": "us-east-1"
},
"kps_enabled": { "type": "boolean" }
},
@@ -1208,6 +1531,7 @@
"properties": {
"entitlement": { "enum": ["disallowed", "allowed"], "type": "string" },
"config": { "$ref": "#/components/schemas/NetworkRestrictionsRequest" },
"old_config": { "$ref": "#/components/schemas/NetworkRestrictionsRequest" },
"status": { "enum": ["stored", "applied"], "type": "string" }
},
"required": ["entitlement", "config", "status"]
@@ -1297,6 +1621,221 @@
"type": "object",
"properties": { "custom_domain": { "type": "string" } },
"required": ["custom_domain"]
},
"UpgradeDatabaseBody": {
"type": "object",
"properties": { "target_version": { "type": "number" } },
"required": ["target_version"]
},
"ProjectVersion": {
"type": "object",
"properties": {
"postgres_version": { "type": "number" },
"app_version": { "type": "string" }
},
"required": ["postgres_version", "app_version"]
},
"ProjectUpgradeEligibilityResponse": {
"type": "object",
"properties": {
"eligible": { "type": "boolean" },
"current_app_version": { "type": "string" },
"latest_app_version": { "type": "string" },
"target_upgrade_versions": {
"type": "array",
"items": { "$ref": "#/components/schemas/ProjectVersion" }
},
"requires_manual_intervention": { "type": "string", "nullable": true },
"potential_breaking_changes": { "type": "array", "items": { "type": "string" } }
},
"required": [
"eligible",
"current_app_version",
"latest_app_version",
"target_upgrade_versions",
"requires_manual_intervention",
"potential_breaking_changes"
]
},
"DatabaseUpgradeStatus": {
"type": "object",
"properties": {
"initiated_at": { "type": "string" },
"target_version": { "type": "number" },
"error": {
"type": "string",
"enum": [
"1_upgraded_instance_launch_failed",
"2_volume_detachchment_from_upgraded_instance_failed",
"3_volume_attachment_to_original_instance_failed",
"4_data_upgrade_initiation_failed",
"5_data_upgrade_completion_failed",
"6_volume_detachchment_from_original_instance_failed",
"7_volume_attachment_to_upgraded_instance_failed",
"8_upgrade_completion_failed"
]
},
"progress": {
"type": "string",
"enum": [
"1_started",
"2_launched_upgraded_instance",
"3_detached_volume_from_upgraded_instance",
"4_attached_volume_to_original_instance",
"5_initiated_data_upgrade",
"6_completed_data_upgrade",
"7_detached_volume_from_original_instance",
"8_attached_volume_to_upgraded_instance",
"9_completed_upgrade"
]
},
"status": { "type": "number", "enum": [0, 1, 2] }
},
"required": ["initiated_at", "target_version", "status"]
},
"DatabaseUpgradeStatusResponse": {
"type": "object",
"properties": {
"databaseUpgradeStatus": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/DatabaseUpgradeStatus" }]
}
},
"required": ["databaseUpgradeStatus"]
},
"ReadOnlyStatusResponse": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"override_enabled": { "type": "boolean" },
"override_active_until": { "type": "string" }
},
"required": ["enabled", "override_enabled", "override_active_until"]
},
"AttributeValue": {
"type": "object",
"properties": {
"name": { "type": "string" },
"names": { "type": "array", "items": { "type": "string" } },
"default": { "type": "object" }
}
},
"AttributeMapping": {
"type": "object",
"properties": {
"keys": {
"type": "object",
"additionalProperties": { "$ref": "#/components/schemas/AttributeValue" }
}
},
"required": ["keys"]
},
"CreateProviderBody": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["saml"],
"description": "What type of provider will be created"
},
"metadata_xml": { "type": "string" },
"metadata_url": { "type": "string" },
"domains": { "type": "array", "items": { "type": "string" } },
"attribute_mapping": { "$ref": "#/components/schemas/AttributeMapping" }
},
"required": ["type"]
},
"SamlDescriptor": {
"type": "object",
"properties": {
"id": { "type": "string" },
"entity_id": { "type": "string" },
"metadata_url": { "type": "string" },
"metadata_xml": { "type": "string" },
"attribute_mapping": { "$ref": "#/components/schemas/AttributeMapping" }
},
"required": ["id", "entity_id"]
},
"Domain": {
"type": "object",
"properties": {
"id": { "type": "string" },
"domain": { "type": "string" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
},
"CreateProviderResponse": {
"type": "object",
"properties": {
"id": { "type": "string" },
"saml": { "$ref": "#/components/schemas/SamlDescriptor" },
"domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
},
"Provider": {
"type": "object",
"properties": {
"id": { "type": "string" },
"saml": { "$ref": "#/components/schemas/SamlDescriptor" },
"domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
},
"ListProvidersResponse": {
"type": "object",
"properties": {
"items": { "type": "array", "items": { "$ref": "#/components/schemas/Provider" } }
},
"required": ["items"]
},
"GetProviderResponse": {
"type": "object",
"properties": {
"id": { "type": "string" },
"saml": { "$ref": "#/components/schemas/SamlDescriptor" },
"domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
},
"UpdateProviderBody": {
"type": "object",
"properties": {
"metadata_xml": { "type": "string" },
"metadata_url": { "type": "string" },
"domains": { "type": "array", "items": { "type": "string" } },
"attribute_mapping": { "$ref": "#/components/schemas/AttributeMapping" }
}
},
"UpdateProviderResponse": {
"type": "object",
"properties": {
"id": { "type": "string" },
"saml": { "$ref": "#/components/schemas/SamlDescriptor" },
"domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
},
"DeleteProviderResponse": {
"type": "object",
"properties": {
"id": { "type": "string" },
"saml": { "$ref": "#/components/schemas/SamlDescriptor" },
"domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
"required": ["id"]
}
}
}
+14 -8
View File
@@ -13,7 +13,8 @@
"excludes": [
"reference_javascript_v1",
"reference_dart_v0",
"reference_python_v2"
"reference_python_v2",
"reference_swift_v1"
]
},
{
@@ -32,7 +33,8 @@
"reference_dart_v0",
"reference_dart_v1",
"reference_python_v2",
"reference_csharp_v0"
"reference_csharp_v0",
"reference_swift_v1"
]
},
{
@@ -44,7 +46,8 @@
"reference_javascript_v2",
"reference_dart_v1",
"reference_python_v2",
"reference_csharp_v0"
"reference_csharp_v0",
"reference_swift_v1"
]
},
{
@@ -297,7 +300,7 @@
"items": [
{
"id": "db-modifiers-select",
"title": "Select the query",
"title": "Return data after inserting",
"slug": "db-modifiers-select",
"product": "database",
"parent": "modifiers",
@@ -305,7 +308,7 @@
},
{
"id": "order",
"title": "Order the query",
"title": "Order the results",
"slug": "order",
"product": "database",
"parent": "modifiers",
@@ -313,7 +316,7 @@
},
{
"id": "limit",
"title": "Limit the query",
"title": "Limit the number of rows returned",
"slug": "limit",
"product": "database",
"parent": "modifiers",
@@ -857,7 +860,10 @@
"title": "Misc",
"excludes": [
"reference_dart_v1",
"reference_dart_v0"
"reference_dart_v0",
"reference_python_v2",
"reference_csharp_v0",
"reference_swift_v1"
],
"items": [
{
@@ -869,4 +875,4 @@
}
]
}
]
]
@@ -0,0 +1,104 @@
[
{
"id": "introduction",
"title": "Introduction",
"slug": "introduction",
"summary": "Introduction",
"type": "markdown"
},
{
"title": "Management API",
"items": [
{
"id": "list-endpoints",
"slug": "list-endpoints",
"title": "List endpoints",
"type": "operation"
},
{
"id": "create-endpoint",
"slug": "create-endpoint",
"title": "Create endpoint",
"type": "operation"
},
{
"id": "delete-endpoint",
"slug": "delete-endpoint",
"title": "Delete endpoint",
"type": "operation"
},
{
"id": "fetch-endpoint",
"slug": "fetch-endpoint",
"title": "Fetch endpoint",
"type": "operation"
},
{
"id": "update-endpoint",
"slug": "update-endpoint",
"title": "Update endpoint",
"type": "operation"
},
{
"id": "list-sources",
"slug": "list-sources",
"title": "List sources",
"type": "operation"
},
{
"id": "create-source",
"slug": "create-source",
"title": "Create source",
"type": "operation"
},
{
"id": "delete-source",
"slug": "delete-source",
"title": "Delete source",
"type": "operation"
},
{
"id": "fetch-source",
"slug": "fetch-source",
"title": "Fetch source",
"type": "operation"
},
{
"id": "update-source",
"slug": "update-source",
"title": "Update source",
"type": "operation"
},
{
"id": "list-teams",
"slug": "list-teams",
"title": "List teams",
"type": "operation"
},
{
"id": "create-team",
"slug": "create-team",
"title": "Create team",
"type": "operation"
},
{
"id": "delete-team",
"slug": "delete-team",
"title": "Delete team",
"type": "operation"
},
{
"id": "fetch-team",
"slug": "fetch-team",
"title": "Fetch team",
"type": "operation"
},
{
"id": "update-team",
"slug": "update-team",
"title": "Update team",
"type": "operation"
}
]
}
]
File diff suppressed because it is too large. Load diff
+102 -58
View File
@@ -418,7 +418,7 @@
"typeArguments": [
{
"type": "reference",
"id": 57,
"id": 58,
"typeArguments": [
{
"type": "reference",
@@ -509,14 +509,14 @@
]
},
{
"id": 35,
"id": 36,
"name": "FunctionsError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 36,
"id": 37,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -530,14 +530,14 @@
],
"signatures": [
{
"id": 37,
"id": 38,
"name": "new FunctionsError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 38,
"id": 39,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -548,7 +548,7 @@
}
},
{
"id": 39,
"id": 40,
"name": "name",
"kind": 32768,
"kindString": "Parameter",
@@ -560,7 +560,7 @@
"defaultValue": "'FunctionsError'"
},
{
"id": 40,
"id": 41,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -575,7 +575,7 @@
],
"type": {
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
},
"overwrites": {
@@ -590,7 +590,7 @@
}
},
{
"id": 41,
"id": 42,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -612,12 +612,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [36]
"children": [37]
},
{
"title": "Properties",
"kind": 1024,
"children": [41]
"children": [42]
}
],
"sources": [
@@ -638,30 +638,30 @@
"extendedBy": [
{
"type": "reference",
"id": 42,
"id": 43,
"name": "FunctionsFetchError"
},
{
"type": "reference",
"id": 47,
"id": 48,
"name": "FunctionsHttpError"
},
{
"type": "reference",
"id": 52,
"id": 53,
"name": "FunctionsRelayError"
}
]
},
{
"id": 42,
"id": 43,
"name": "FunctionsFetchError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 43,
"id": 44,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -675,14 +675,14 @@
],
"signatures": [
{
"id": 44,
"id": 45,
"name": "new FunctionsFetchError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 45,
"id": 46,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -695,24 +695,24 @@
],
"type": {
"type": "reference",
"id": 42,
"id": 43,
"name": "FunctionsFetchError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 46,
"id": 47,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -730,7 +730,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -739,12 +739,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [43]
"children": [44]
},
{
"title": "Properties",
"kind": 1024,
"children": [46]
"children": [47]
}
],
"sources": [
@@ -757,20 +757,20 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
},
{
"id": 47,
"id": 48,
"name": "FunctionsHttpError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 48,
"id": 49,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -784,14 +784,14 @@
],
"signatures": [
{
"id": 49,
"id": 50,
"name": "new FunctionsHttpError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 50,
"id": 51,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -804,24 +804,24 @@
],
"type": {
"type": "reference",
"id": 47,
"id": 48,
"name": "FunctionsHttpError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 51,
"id": 52,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -839,7 +839,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -848,12 +848,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [48]
"children": [49]
},
{
"title": "Properties",
"kind": 1024,
"children": [51]
"children": [52]
}
],
"sources": [
@@ -866,20 +866,20 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
},
{
"id": 52,
"id": 53,
"name": "FunctionsRelayError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 53,
"id": 54,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -893,14 +893,14 @@
],
"signatures": [
{
"id": 54,
"id": 55,
"name": "new FunctionsRelayError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 55,
"id": 56,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -913,24 +913,24 @@
],
"type": {
"type": "reference",
"id": 52,
"id": 53,
"name": "FunctionsRelayError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 56,
"id": 57,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -948,7 +948,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -957,12 +957,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [53]
"children": [54]
},
{
"title": "Properties",
"kind": 1024,
"children": [56]
"children": [57]
}
],
"sources": [
@@ -975,7 +975,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
@@ -1003,7 +1003,7 @@
"flags": {},
"children": [
{
"id": 34,
"id": 35,
"name": "body",
"kind": 1024,
"kindString": "Property",
@@ -1016,7 +1016,7 @@
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"line": 56,
"character": 2
}
],
@@ -1142,13 +1142,57 @@
}
}
}
},
{
"id": 34,
"name": "method",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "The HTTP verb of the request"
},
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"character": 2
}
],
"type": {
"type": "union",
"types": [
{
"type": "literal",
"value": "POST"
},
{
"type": "literal",
"value": "GET"
},
{
"type": "literal",
"value": "PUT"
},
{
"type": "literal",
"value": "PATCH"
},
{
"type": "literal",
"value": "DELETE"
}
]
}
}
],
"groups": [
{
"title": "Properties",
"kind": 1024,
"children": [34, 30]
"children": [35, 30, 34]
}
],
"sources": [
@@ -1162,7 +1206,7 @@
}
},
{
"id": 57,
"id": 58,
"name": "FunctionsResponse",
"kind": 4194304,
"kindString": "Type alias",
@@ -1176,7 +1220,7 @@
],
"typeParameter": [
{
"id": 58,
"id": 59,
"name": "T",
"kind": 131072,
"kindString": "Type parameter",
@@ -1191,7 +1235,7 @@
"typeArguments": [
{
"type": "reference",
"id": 58,
"id": 59,
"name": "T"
}
],
@@ -1209,12 +1253,12 @@
{
"title": "Classes",
"kind": 128,
"children": [1, 35, 42, 47, 52]
"children": [1, 36, 43, 48, 53]
},
{
"title": "Type Aliases",
"kind": 4194304,
"children": [28, 57]
"children": [28, 58]
}
],
"sources": [
@@ -432,7 +432,7 @@
"flags": {},
"children": [
{
"id": 34,
"id": 35,
"name": "body",
"kind": 1024,
"kindString": "Property",
@@ -445,7 +445,7 @@
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"line": 56,
"character": 2
}
],
@@ -571,13 +571,57 @@
}
}
}
},
{
"id": 34,
"name": "method",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "The HTTP verb of the request"
},
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"character": 2
}
],
"type": {
"type": "union",
"types": [
{
"type": "literal",
"value": "POST"
},
{
"type": "literal",
"value": "GET"
},
{
"type": "literal",
"value": "PUT"
},
{
"type": "literal",
"value": "PATCH"
},
{
"type": "literal",
"value": "DELETE"
}
]
}
}
],
"groups": [
{
"title": "Properties",
"kind": 1024,
"children": [34, 30]
"children": [35, 30, 34]
}
],
"sources": [
@@ -599,7 +643,7 @@
"typeArguments": [
{
"type": "reference",
"id": 57,
"id": 58,
"typeArguments": [
{
"type": "reference",
@@ -690,14 +734,14 @@
]
},
{
"id": 35,
"id": 36,
"name": "FunctionsError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 36,
"id": 37,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -711,14 +755,14 @@
],
"signatures": [
{
"id": 37,
"id": 38,
"name": "new FunctionsError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 38,
"id": 39,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -729,7 +773,7 @@
}
},
{
"id": 39,
"id": 40,
"name": "name",
"kind": 32768,
"kindString": "Parameter",
@@ -741,7 +785,7 @@
"defaultValue": "'FunctionsError'"
},
{
"id": 40,
"id": 41,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -756,7 +800,7 @@
],
"type": {
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
},
"overwrites": {
@@ -771,7 +815,7 @@
}
},
{
"id": 41,
"id": 42,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -793,12 +837,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [36]
"children": [37]
},
{
"title": "Properties",
"kind": 1024,
"children": [41]
"children": [42]
}
],
"sources": [
@@ -819,30 +863,30 @@
"extendedBy": [
{
"type": "reference",
"id": 42,
"id": 43,
"name": "FunctionsFetchError"
},
{
"type": "reference",
"id": 47,
"id": 48,
"name": "FunctionsHttpError"
},
{
"type": "reference",
"id": 52,
"id": 53,
"name": "FunctionsRelayError"
}
]
},
{
"id": 42,
"id": 43,
"name": "FunctionsFetchError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 43,
"id": 44,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -856,14 +900,14 @@
],
"signatures": [
{
"id": 44,
"id": 45,
"name": "new FunctionsFetchError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 45,
"id": 46,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -876,24 +920,24 @@
],
"type": {
"type": "reference",
"id": 42,
"id": 43,
"name": "FunctionsFetchError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 46,
"id": 47,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -911,7 +955,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -920,12 +964,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [43]
"children": [44]
},
{
"title": "Properties",
"kind": 1024,
"children": [46]
"children": [47]
}
],
"sources": [
@@ -938,20 +982,20 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
},
{
"id": 47,
"id": 48,
"name": "FunctionsHttpError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 48,
"id": 49,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -965,14 +1009,14 @@
],
"signatures": [
{
"id": 49,
"id": 50,
"name": "new FunctionsHttpError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 50,
"id": 51,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -985,24 +1029,24 @@
],
"type": {
"type": "reference",
"id": 47,
"id": 48,
"name": "FunctionsHttpError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 51,
"id": 52,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -1020,7 +1064,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -1029,12 +1073,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [48]
"children": [49]
},
{
"title": "Properties",
"kind": 1024,
"children": [51]
"children": [52]
}
],
"sources": [
@@ -1047,20 +1091,20 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
},
{
"id": 52,
"id": 53,
"name": "FunctionsRelayError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 53,
"id": 54,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -1074,14 +1118,14 @@
],
"signatures": [
{
"id": 54,
"id": 55,
"name": "new FunctionsRelayError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 55,
"id": 56,
"name": "context",
"kind": 32768,
"kindString": "Parameter",
@@ -1094,24 +1138,24 @@
],
"type": {
"type": "reference",
"id": 52,
"id": 53,
"name": "FunctionsRelayError"
},
"overwrites": {
"type": "reference",
"id": 37,
"id": 38,
"name": "FunctionsError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 36,
"id": 37,
"name": "FunctionsError.constructor"
}
},
{
"id": 56,
"id": 57,
"name": "context",
"kind": 1024,
"kindString": "Property",
@@ -1129,7 +1173,7 @@
},
"inheritedFrom": {
"type": "reference",
"id": 41,
"id": 42,
"name": "FunctionsError.context"
}
}
@@ -1138,12 +1182,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [53]
"children": [54]
},
{
"title": "Properties",
"kind": 1024,
"children": [56]
"children": [57]
}
],
"sources": [
@@ -1156,7 +1200,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 35,
"id": 36,
"name": "FunctionsError"
}
]
@@ -1184,7 +1228,7 @@
"flags": {},
"children": [
{
"id": 34,
"id": 35,
"name": "body",
"kind": 1024,
"kindString": "Property",
@@ -1197,7 +1241,7 @@
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"line": 56,
"character": 2
}
],
@@ -1323,13 +1367,57 @@
}
}
}
},
{
"id": 34,
"name": "method",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "The HTTP verb of the request"
},
"sources": [
{
"fileName": "src/types.ts",
"line": 52,
"character": 2
}
],
"type": {
"type": "union",
"types": [
{
"type": "literal",
"value": "POST"
},
{
"type": "literal",
"value": "GET"
},
{
"type": "literal",
"value": "PUT"
},
{
"type": "literal",
"value": "PATCH"
},
{
"type": "literal",
"value": "DELETE"
}
]
}
}
],
"groups": [
{
"title": "Properties",
"kind": 1024,
"children": [34, 30]
"children": [35, 30, 34]
}
],
"sources": [
@@ -1343,7 +1431,7 @@
}
},
{
"id": 57,
"id": 58,
"name": "FunctionsResponse",
"kind": 4194304,
"kindString": "Type alias",
@@ -1357,7 +1445,7 @@
],
"typeParameter": [
{
"id": 58,
"id": 59,
"name": "T",
"kind": 131072,
"kindString": "Type parameter",
@@ -1374,12 +1462,12 @@
{
"title": "Classes",
"kind": 128,
"children": [1, 35, 42, 47, 52]
"children": [1, 36, 43, 48, 53]
},
{
"title": "Type Aliases",
"kind": 4194304,
"children": [28, 57]
"children": [28, 58]
}
],
"sources": [
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+93 -70
View File
@@ -13,14 +13,14 @@
"flags": {},
"children": [
{
"id": 403,
"id": 404,
"name": "StorageApiError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 404,
"id": 405,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -34,14 +34,14 @@
],
"signatures": [
{
"id": 405,
"id": 406,
"name": "new StorageApiError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 406,
"id": 407,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -52,7 +52,7 @@
}
},
{
"id": 407,
"id": 408,
"name": "status",
"kind": 32768,
"kindString": "Parameter",
@@ -65,24 +65,24 @@
],
"type": {
"type": "reference",
"id": 403,
"id": 404,
"name": "StorageApiError"
},
"overwrites": {
"type": "reference",
"id": 400,
"id": 401,
"name": "StorageError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 399,
"id": 400,
"name": "StorageError.constructor"
}
},
{
"id": 408,
"id": 409,
"name": "status",
"kind": 1024,
"kindString": "Property",
@@ -100,7 +100,7 @@
}
},
{
"id": 409,
"id": 410,
"name": "toJSON",
"kind": 2048,
"kindString": "Method",
@@ -114,7 +114,7 @@
],
"signatures": [
{
"id": 410,
"id": 411,
"name": "toJSON",
"kind": 4096,
"kindString": "Call signature",
@@ -122,14 +122,14 @@
"type": {
"type": "reflection",
"declaration": {
"id": 411,
"id": 412,
"name": "__type",
"kind": 65536,
"kindString": "Type literal",
"flags": {},
"children": [
{
"id": 413,
"id": 414,
"name": "message",
"kind": 1024,
"kindString": "Property",
@@ -148,7 +148,7 @@
"defaultValue": "..."
},
{
"id": 412,
"id": 413,
"name": "name",
"kind": 1024,
"kindString": "Property",
@@ -167,7 +167,7 @@
"defaultValue": "..."
},
{
"id": 414,
"id": 415,
"name": "status",
"kind": 1024,
"kindString": "Property",
@@ -190,7 +190,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [413, 412, 414]
"children": [414, 413, 415]
}
]
}
@@ -203,17 +203,17 @@
{
"title": "Constructors",
"kind": 512,
"children": [404]
"children": [405]
},
{
"title": "Properties",
"kind": 1024,
"children": [408]
"children": [409]
},
{
"title": "Methods",
"kind": 2048,
"children": [409]
"children": [410]
}
],
"sources": [
@@ -226,7 +226,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
]
@@ -606,7 +606,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -815,7 +815,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1024,7 +1024,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1248,7 +1248,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1412,7 +1412,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1668,7 +1668,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1731,14 +1731,14 @@
]
},
{
"id": 398,
"id": 399,
"name": "StorageError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 399,
"id": 400,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -1752,14 +1752,14 @@
],
"signatures": [
{
"id": 400,
"id": 401,
"name": "new StorageError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 401,
"id": 402,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -1772,7 +1772,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
},
"overwrites": {
@@ -1791,7 +1791,7 @@
{
"title": "Constructors",
"kind": 512,
"children": [399]
"children": [400]
}
],
"sources": [
@@ -1812,25 +1812,25 @@
"extendedBy": [
{
"type": "reference",
"id": 403,
"id": 404,
"name": "StorageApiError"
},
{
"type": "reference",
"id": 416,
"id": 417,
"name": "StorageUnknownError"
}
]
},
{
"id": 416,
"id": 417,
"name": "StorageUnknownError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 417,
"id": 418,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -1844,14 +1844,14 @@
],
"signatures": [
{
"id": 418,
"id": 419,
"name": "new StorageUnknownError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 419,
"id": 420,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -1862,7 +1862,7 @@
}
},
{
"id": 420,
"id": 421,
"name": "originalError",
"kind": 32768,
"kindString": "Parameter",
@@ -1875,24 +1875,24 @@
],
"type": {
"type": "reference",
"id": 416,
"id": 417,
"name": "StorageUnknownError"
},
"overwrites": {
"type": "reference",
"id": 400,
"id": 401,
"name": "StorageError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 399,
"id": 400,
"name": "StorageError.constructor"
}
},
{
"id": 421,
"id": 422,
"name": "originalError",
"kind": 1024,
"kindString": "Property",
@@ -1914,12 +1914,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [417]
"children": [418]
},
{
"title": "Properties",
"kind": 1024,
"children": [421]
"children": [422]
}
],
"sources": [
@@ -1932,7 +1932,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
]
@@ -2634,7 +2634,7 @@
"flags": {},
"children": [
{
"id": 394,
"id": 395,
"name": "format",
"kind": 1024,
"kindString": "Property",
@@ -2648,7 +2648,7 @@
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 98,
"line": 102,
"character": 2
}
],
@@ -2680,6 +2680,29 @@
"name": "number"
}
},
{
"id": 394,
"name": "quality",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "Set the quality of the returned image, this is percentage based, default 80"
},
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 95,
"character": 2
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
},
{
"id": 393,
"name": "resize",
@@ -2744,7 +2767,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [394, 392, 393, 391]
"children": [395, 392, 394, 393, 391]
}
],
"sources": [
@@ -2756,7 +2779,7 @@
]
},
{
"id": 395,
"id": 396,
"name": "isStorageError",
"kind": 64,
"kindString": "Function",
@@ -2770,14 +2793,14 @@
],
"signatures": [
{
"id": 396,
"id": 397,
"name": "isStorageError",
"kind": 4096,
"kindString": "Call signature",
"flags": {},
"parameters": [
{
"id": 397,
"id": 398,
"name": "error",
"kind": 32768,
"kindString": "Parameter",
@@ -2794,7 +2817,7 @@
"asserts": false,
"targetType": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -2806,7 +2829,7 @@
{
"title": "Classes",
"kind": 128,
"children": [403, 266, 398, 416]
"children": [404, 266, 399, 417]
},
{
"title": "Interfaces",
@@ -2816,7 +2839,7 @@
{
"title": "Functions",
"kind": 64,
"children": [395]
"children": [396]
}
],
"sources": [
@@ -3199,7 +3222,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3398,7 +3421,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3597,7 +3620,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3764,7 +3787,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3918,7 +3941,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4164,7 +4187,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4602,7 +4625,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4899,7 +4922,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -5230,7 +5253,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -5450,7 +5473,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -5846,7 +5869,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6059,7 +6082,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6232,7 +6255,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6526,7 +6549,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6820,7 +6843,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -13,14 +13,14 @@
"flags": {},
"children": [
{
"id": 403,
"id": 404,
"name": "StorageApiError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 404,
"id": 405,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -34,14 +34,14 @@
],
"signatures": [
{
"id": 405,
"id": 406,
"name": "new StorageApiError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 406,
"id": 407,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -52,7 +52,7 @@
}
},
{
"id": 407,
"id": 408,
"name": "status",
"kind": 32768,
"kindString": "Parameter",
@@ -65,24 +65,24 @@
],
"type": {
"type": "reference",
"id": 403,
"id": 404,
"name": "StorageApiError"
},
"overwrites": {
"type": "reference",
"id": 400,
"id": 401,
"name": "StorageError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 399,
"id": 400,
"name": "StorageError.constructor"
}
},
{
"id": 408,
"id": 409,
"name": "status",
"kind": 1024,
"kindString": "Property",
@@ -100,7 +100,7 @@
}
},
{
"id": 409,
"id": 410,
"name": "toJSON",
"kind": 2048,
"kindString": "Method",
@@ -114,7 +114,7 @@
],
"signatures": [
{
"id": 410,
"id": 411,
"name": "toJSON",
"kind": 4096,
"kindString": "Call signature",
@@ -122,14 +122,14 @@
"type": {
"type": "reflection",
"declaration": {
"id": 411,
"id": 412,
"name": "__type",
"kind": 65536,
"kindString": "Type literal",
"flags": {},
"children": [
{
"id": 413,
"id": 414,
"name": "message",
"kind": 1024,
"kindString": "Property",
@@ -148,7 +148,7 @@
"defaultValue": "..."
},
{
"id": 412,
"id": 413,
"name": "name",
"kind": 1024,
"kindString": "Property",
@@ -167,7 +167,7 @@
"defaultValue": "..."
},
{
"id": 414,
"id": 415,
"name": "status",
"kind": 1024,
"kindString": "Property",
@@ -190,7 +190,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [413, 412, 414]
"children": [414, 413, 415]
}
]
}
@@ -203,17 +203,17 @@
{
"title": "Constructors",
"kind": 512,
"children": [404]
"children": [405]
},
{
"title": "Properties",
"kind": 1024,
"children": [408]
"children": [409]
},
{
"title": "Methods",
"kind": 2048,
"children": [409]
"children": [410]
}
],
"sources": [
@@ -226,7 +226,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
]
@@ -606,7 +606,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -815,7 +815,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1024,7 +1024,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1248,7 +1248,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1412,7 +1412,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1668,7 +1668,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -1731,14 +1731,14 @@
]
},
{
"id": 398,
"id": 399,
"name": "StorageError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 399,
"id": 400,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -1752,14 +1752,14 @@
],
"signatures": [
{
"id": 400,
"id": 401,
"name": "new StorageError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 401,
"id": 402,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -1772,7 +1772,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
},
"overwrites": {
@@ -1791,7 +1791,7 @@
{
"title": "Constructors",
"kind": 512,
"children": [399]
"children": [400]
}
],
"sources": [
@@ -1812,25 +1812,25 @@
"extendedBy": [
{
"type": "reference",
"id": 403,
"id": 404,
"name": "StorageApiError"
},
{
"type": "reference",
"id": 416,
"id": 417,
"name": "StorageUnknownError"
}
]
},
{
"id": 416,
"id": 417,
"name": "StorageUnknownError",
"kind": 128,
"kindString": "Class",
"flags": {},
"children": [
{
"id": 417,
"id": 418,
"name": "constructor",
"kind": 512,
"kindString": "Constructor",
@@ -1844,14 +1844,14 @@
],
"signatures": [
{
"id": 418,
"id": 419,
"name": "new StorageUnknownError",
"kind": 16384,
"kindString": "Constructor signature",
"flags": {},
"parameters": [
{
"id": 419,
"id": 420,
"name": "message",
"kind": 32768,
"kindString": "Parameter",
@@ -1862,7 +1862,7 @@
}
},
{
"id": 420,
"id": 421,
"name": "originalError",
"kind": 32768,
"kindString": "Parameter",
@@ -1875,24 +1875,24 @@
],
"type": {
"type": "reference",
"id": 416,
"id": 417,
"name": "StorageUnknownError"
},
"overwrites": {
"type": "reference",
"id": 400,
"id": 401,
"name": "StorageError.constructor"
}
}
],
"overwrites": {
"type": "reference",
"id": 399,
"id": 400,
"name": "StorageError.constructor"
}
},
{
"id": 421,
"id": 422,
"name": "originalError",
"kind": 1024,
"kindString": "Property",
@@ -1914,12 +1914,12 @@
{
"title": "Constructors",
"kind": 512,
"children": [417]
"children": [418]
},
{
"title": "Properties",
"kind": 1024,
"children": [421]
"children": [422]
}
],
"sources": [
@@ -1932,7 +1932,7 @@
"extendedTypes": [
{
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
]
@@ -2828,7 +2828,7 @@
"flags": {},
"children": [
{
"id": 394,
"id": 395,
"name": "format",
"kind": 1024,
"kindString": "Property",
@@ -2842,7 +2842,7 @@
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 98,
"line": 102,
"character": 2
}
],
@@ -2874,6 +2874,29 @@
"name": "number"
}
},
{
"id": 394,
"name": "quality",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "Set the quality of the returned image, this is percentage based, default 80"
},
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 95,
"character": 2
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
},
{
"id": 393,
"name": "resize",
@@ -2938,7 +2961,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [394, 392, 393, 391]
"children": [395, 392, 394, 393, 391]
}
],
"sources": [
@@ -2950,7 +2973,7 @@
]
},
{
"id": 395,
"id": 396,
"name": "isStorageError",
"kind": 64,
"kindString": "Function",
@@ -2964,14 +2987,14 @@
],
"signatures": [
{
"id": 396,
"id": 397,
"name": "isStorageError",
"kind": 4096,
"kindString": "Call signature",
"flags": {},
"parameters": [
{
"id": 397,
"id": 398,
"name": "error",
"kind": 32768,
"kindString": "Parameter",
@@ -2988,7 +3011,7 @@
"asserts": false,
"targetType": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3000,7 +3023,7 @@
{
"title": "Classes",
"kind": 128,
"children": [403, 266, 398, 416]
"children": [404, 266, 399, 417]
},
{
"title": "Interfaces",
@@ -3010,7 +3033,7 @@
{
"title": "Functions",
"kind": 64,
"children": [395]
"children": [396]
}
],
"sources": [
@@ -3393,7 +3416,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3592,7 +3615,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3791,7 +3814,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -3958,7 +3981,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4112,7 +4135,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4358,7 +4381,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4796,7 +4819,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -4951,7 +4974,7 @@
"flags": {},
"children": [
{
"id": 394,
"id": 395,
"name": "format",
"kind": 1024,
"kindString": "Property",
@@ -4965,7 +4988,7 @@
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 98,
"line": 102,
"character": 2
}
],
@@ -4997,6 +5020,29 @@
"name": "number"
}
},
{
"id": 394,
"name": "quality",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "Set the quality of the returned image, this is percentage based, default 80"
},
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 95,
"character": 2
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
},
{
"id": 393,
"name": "resize",
@@ -5061,7 +5107,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [394, 392, 393, 391]
"children": [395, 392, 394, 393, 391]
}
],
"sources": [
@@ -5222,7 +5268,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -5553,7 +5599,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -5662,7 +5708,7 @@
"flags": {},
"children": [
{
"id": 394,
"id": 395,
"name": "format",
"kind": 1024,
"kindString": "Property",
@@ -5676,7 +5722,7 @@
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 98,
"line": 102,
"character": 2
}
],
@@ -5708,6 +5754,29 @@
"name": "number"
}
},
{
"id": 394,
"name": "quality",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "Set the quality of the returned image, this is percentage based, default 80"
},
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 95,
"character": 2
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
},
{
"id": 393,
"name": "resize",
@@ -5772,7 +5841,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [394, 392, 393, 391]
"children": [395, 392, 394, 393, 391]
}
],
"sources": [
@@ -5902,7 +5971,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6043,7 +6112,7 @@
"flags": {},
"children": [
{
"id": 394,
"id": 395,
"name": "format",
"kind": 1024,
"kindString": "Property",
@@ -6057,7 +6126,7 @@
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 98,
"line": 102,
"character": 2
}
],
@@ -6089,6 +6158,29 @@
"name": "number"
}
},
{
"id": 394,
"name": "quality",
"kind": 1024,
"kindString": "Property",
"flags": {
"isOptional": true
},
"comment": {
"shortText": "Set the quality of the returned image, this is percentage based, default 80"
},
"sources": [
{
"fileName": "src/lib/types.ts",
"line": 95,
"character": 2
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
},
{
"id": 393,
"name": "resize",
@@ -6153,7 +6245,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [394, 392, 393, 391]
"children": [395, 392, 394, 393, 391]
}
],
"sources": [
@@ -6654,7 +6746,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -6867,7 +6959,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -7040,7 +7132,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -7426,7 +7518,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
@@ -7812,7 +7904,7 @@
],
"type": {
"type": "reference",
"id": 398,
"id": 399,
"name": "StorageError"
}
}
+111 -47
View File
@@ -269,7 +269,7 @@
}
},
{
"id": 115,
"id": 116,
"name": "authUrl",
"kind": 1024,
"kindString": "Property",
@@ -279,7 +279,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 57,
"line": 58,
"character": 12
}
],
@@ -356,10 +356,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -398,7 +409,7 @@
}
},
{
"id": 117,
"id": 118,
"name": "functionsUrl",
"kind": 1024,
"kindString": "Property",
@@ -408,7 +419,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 59,
"line": 60,
"character": 12
}
],
@@ -467,18 +478,16 @@
}
},
{
"id": 118,
"id": 114,
"name": "realtime",
"kind": 1024,
"kindString": "Property",
"flags": {
"isProtected": true
},
"flags": {},
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 60,
"character": 12
"line": 55,
"character": 2
}
],
"type": {
@@ -489,7 +498,7 @@
}
},
{
"id": 114,
"id": 115,
"name": "realtimeUrl",
"kind": 1024,
"kindString": "Property",
@@ -499,7 +508,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 56,
"line": 57,
"character": 12
}
],
@@ -600,7 +609,7 @@
}
},
{
"id": 116,
"id": 117,
"name": "storageUrl",
"kind": 1024,
"kindString": "Property",
@@ -610,7 +619,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 58,
"line": 59,
"character": 12
}
],
@@ -976,10 +985,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -1375,6 +1395,10 @@
"elementType": {
"type": "union",
"types": [
{
"type": "literal",
"value": "error"
},
{
"type": "literal",
"value": "ok"
@@ -1382,10 +1406,6 @@
{
"type": "literal",
"value": "timed out"
},
{
"type": "literal",
"value": "error"
}
]
}
@@ -1445,6 +1465,10 @@
{
"type": "union",
"types": [
{
"type": "literal",
"value": "error"
},
{
"type": "literal",
"value": "ok"
@@ -1452,10 +1476,6 @@
{
"type": "literal",
"value": "timed out"
},
{
"type": "literal",
"value": "error"
}
]
}
@@ -1758,7 +1778,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [113, 115, 126, 121, 117, 127, 118, 114, 119, 120, 116, 132, 131]
"children": [113, 116, 126, 121, 118, 127, 114, 115, 119, 120, 117, 132, 131]
},
{
"title": "Accessors",
@@ -2329,10 +2349,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -2394,10 +2425,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -2489,10 +2531,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -2554,10 +2607,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -700,7 +700,7 @@
}
},
{
"id": 115,
"id": 116,
"name": "authUrl",
"kind": 1024,
"kindString": "Property",
@@ -710,7 +710,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 57,
"line": 58,
"character": 12
}
],
@@ -787,10 +787,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -829,7 +840,7 @@
}
},
{
"id": 117,
"id": 118,
"name": "functionsUrl",
"kind": 1024,
"kindString": "Property",
@@ -839,7 +850,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 59,
"line": 60,
"character": 12
}
],
@@ -898,18 +909,16 @@
}
},
{
"id": 118,
"id": 114,
"name": "realtime",
"kind": 1024,
"kindString": "Property",
"flags": {
"isProtected": true
},
"flags": {},
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 60,
"character": 12
"line": 55,
"character": 2
}
],
"type": {
@@ -920,7 +929,7 @@
}
},
{
"id": 114,
"id": 115,
"name": "realtimeUrl",
"kind": 1024,
"kindString": "Property",
@@ -930,7 +939,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 56,
"line": 57,
"character": 12
}
],
@@ -1031,7 +1040,7 @@
}
},
{
"id": 116,
"id": 117,
"name": "storageUrl",
"kind": 1024,
"kindString": "Property",
@@ -1041,7 +1050,7 @@
"sources": [
{
"fileName": "src/SupabaseClient.ts",
"line": 58,
"line": 59,
"character": 12
}
],
@@ -1427,10 +1436,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -1828,6 +1848,10 @@
"elementType": {
"type": "union",
"types": [
{
"type": "literal",
"value": "error"
},
{
"type": "literal",
"value": "ok"
@@ -1835,10 +1859,6 @@
{
"type": "literal",
"value": "timed out"
},
{
"type": "literal",
"value": "error"
}
]
}
@@ -1898,6 +1918,10 @@
{
"type": "union",
"types": [
{
"type": "literal",
"value": "error"
},
{
"type": "literal",
"value": "ok"
@@ -1905,10 +1929,6 @@
{
"type": "literal",
"value": "timed out"
},
{
"type": "literal",
"value": "error"
}
]
}
@@ -2212,7 +2232,7 @@
{
"title": "Properties",
"kind": 1024,
"children": [113, 115, 126, 121, 117, 127, 118, 114, 119, 120, 116, 132, 131]
"children": [113, 116, 126, 121, 118, 127, 114, 115, 119, 120, 117, 132, 131]
},
{
"title": "Accessors",
@@ -3214,10 +3234,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -3279,10 +3310,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -3374,10 +3416,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
@@ -3439,10 +3492,21 @@
"kindString": "Parameter",
"flags": {},
"type": {
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
"type": "union",
"types": [
{
"type": "reference",
"qualifiedName": "RequestInfo",
"package": "typescript",
"name": "RequestInfo"
},
{
"type": "reference",
"qualifiedName": "URL",
"package": "typescript",
"name": "URL"
}
]
}
},
{
+15 -15
View File
@@ -768,10 +768,10 @@ functions:
- schema: public
name: countries
content: |
| name | id |
| :-----------------------|------:|
| Afghanistan | 1 |
| Albania | 2 |
| name | id |
| :-----------------------|------:|
| Afghanistan | 1 |
| Albania | 2 |
| Algeria | 3 |
response: |
{
@@ -811,10 +811,10 @@ functions:
- schema: public
name: countries
content: |
| name | id |
| :-----------------------|------:|
| Afghanistan | 1 |
| Albania | 2 |
| name | id |
| :-----------------------|------:|
| Afghanistan | 1 |
| Albania | 2 |
| Algeria | 3 |
response: |
{
@@ -873,16 +873,16 @@ functions:
- schema: public
name: countries
content: |
| name | id |
| :-----------------------|------:|
| Germany | 1 |
| name | id |
| :-----------------------|------:|
| Germany | 1 |
| Indonesia | 2 |
- schema: public
name: cities
content: |
| name | id |
| :-----------------------|------:|
| Bali | 1 |
| name | id |
| :-----------------------|------:|
| Bali | 1 |
| Munich | 2 |
response: |
{
@@ -4209,7 +4209,7 @@ functions:
- id: Using Modifiers
description: |
Filters work on the row level—they allows you to return rows that
Filters work on the row level—they allow you to return rows that
only match certain conditions without changing the shape of the rows.
Modifiers are everything that don't fit that definition—allowing you to
change the format of the response (e.g., returning a CSV string).
+142 -2
View File
@@ -43,7 +43,9 @@
"properties": {
"name": { "type": "string", "example": "avatars" },
"id": { "type": "string", "example": "avatars" },
"public": { "type": "boolean", "example": false }
"public": { "type": "boolean", "example": false },
"file_size_limit": { "anyOf": [{ "type": "integer" }, { "type": "string" }] },
"allowed_mime_types": { "type": "array", "items": { "type": "string" } }
},
"required": ["name"]
}
@@ -111,6 +113,11 @@
"name": { "type": "string" },
"owner": { "type": "string" },
"public": { "type": "boolean" },
"file_size_limit": { "type": "integer" },
"allowed_mime_types": {
"type": ["null", "array"],
"items": { "type": "string" }
},
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
@@ -237,6 +244,11 @@
"name": { "type": "string" },
"owner": { "type": "string" },
"public": { "type": "boolean" },
"file_size_limit": { "type": "integer" },
"allowed_mime_types": {
"type": ["null", "array"],
"items": { "type": "string" }
},
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
@@ -278,7 +290,11 @@
"application/json": {
"schema": {
"type": "object",
"properties": { "public": { "type": "boolean", "example": false } }
"properties": {
"public": { "type": "boolean", "example": false },
"file_size_limit": { "anyOf": [{ "type": "integer" }, { "type": "string" }] },
"allowed_mime_types": { "type": "array", "items": { "type": "string" } }
}
}
}
}
@@ -611,6 +627,7 @@
"owner": { "type": "string" },
"id": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"updated_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"version": { "type": "string" },
"created_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"last_accessed_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"metadata": {
@@ -626,6 +643,11 @@
"name": { "type": "string" },
"owner": { "type": "string" },
"public": { "type": "boolean" },
"file_size_limit": { "type": "integer" },
"allowed_mime_types": {
"type": ["null", "array"],
"items": { "type": "string" }
},
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
@@ -708,6 +730,118 @@
}
}
},
"/object/upload/sign/{bucketName}/{wildcard}": {
"post": {
"summary": "Generate a presigned url to upload an object",
"tags": ["object"],
"parameters": [
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": { "type": "string" },
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"description": "Successful response",
"type": "object",
"properties": {
"url": {
"type": "string",
"example": "/object/sign/upload/avatars/folder/cat.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJhdmF0YXJzL2ZvbGRlci9jYXQucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.s7Gt8ME80iREVxPhH01ZNv8oUn4XtaWsmiQ5csiUHn4"
}
},
"required": ["url"]
}
}
}
},
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": { "description": "Error response", "$ref": "#/components/schemas/def-1" }
}
}
}
}
},
"put": {
"summary": "Uploads an object via a presigned URL",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJidWNrZXQyL3B1YmxpYy9zYWRjYXQtdXBsb2FkMjMucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.uBQcXzuvXxfw-9WgzWMBfE_nR3VOgpvfZe032sfLSSk"
},
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJidWNrZXQyL3B1YmxpYy9zYWRjYXQtdXBsb2FkMjMucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.uBQcXzuvXxfw-9WgzWMBfE_nR3VOgpvfZe032sfLSSk",
"in": "query",
"name": "token",
"required": true
},
{
"schema": { "type": "string", "example": "avatars" },
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": { "type": "string", "example": "folder/cat.png" },
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"description": "Successful response",
"type": "object",
"properties": {
"Key": { "type": "string", "example": "projectref/avatars/folder/cat.png" }
},
"required": ["Key"]
}
}
}
},
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/def-1", "description": "Error response" }
}
}
}
}
}
},
"/object/sign/{bucketName}/{wildcard}": {
"post": {
"summary": "Generate a presigned url to retrieve an object",
@@ -1031,6 +1165,7 @@
"owner": { "type": "string" },
"id": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"updated_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"version": { "type": "string" },
"created_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"last_accessed_at": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"metadata": {
@@ -1046,6 +1181,11 @@
"name": { "type": "string" },
"owner": { "type": "string" },
"public": { "type": "boolean" },
"file_size_limit": { "type": "integer" },
"allowed_mime_types": {
"type": ["null", "array"],
"items": { "type": "string" }
},
"created_at": { "type": "string" },
"updated_at": { "type": "string" }
},
+1 -1
View File
@@ -3548,7 +3548,7 @@ functions:
- id: using-modifiers
title: Using Modifiers
description: |
Filters work on the row level—they allows you to return rows that
Filters work on the row level—they allow you to return rows that
only match certain conditions without changing the shape of the rows.
Modifiers are everything that don't fit that definition—allowing you to
change the format of the response (e.g., returning a CSV string).
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -58,6 +58,22 @@
"public": {
"type": "boolean",
"example": false
},
"file_size_limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"allowed_mime_types": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["name"]
@@ -159,6 +175,15 @@
"public": {
"type": "boolean"
},
"file_size_limit": {
"type": "integer"
},
"allowed_mime_types": {
"type": ["null", "array"],
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
@@ -342,6 +367,15 @@
"public": {
"type": "boolean"
},
"file_size_limit": {
"type": "integer"
},
"allowed_mime_types": {
"type": ["null", "array"],
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
@@ -407,6 +441,22 @@
"public": {
"type": "boolean",
"example": false
},
"file_size_limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"allowed_mime_types": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
@@ -923,6 +973,9 @@
}
]
},
"version": {
"type": "string"
},
"created_at": {
"anyOf": [
{
@@ -969,6 +1022,15 @@
"public": {
"type": "boolean"
},
"file_size_limit": {
"type": "integer"
},
"allowed_mime_types": {
"type": ["null", "array"],
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
@@ -1097,6 +1159,167 @@
}
}
},
"/object/upload/sign/{bucketName}/{wildcard}": {
"post": {
"summary": "Generate a presigned url to upload an object",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
},
{
"in": "header",
"name": "authorization",
"required": true,
"schema": {
"type": "string"
},
"example": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs"
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"description": "Successful response",
"type": "object",
"properties": {
"url": {
"type": "string",
"example": "/object/sign/upload/avatars/folder/cat.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJhdmF0YXJzL2ZvbGRlci9jYXQucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.s7Gt8ME80iREVxPhH01ZNv8oUn4XtaWsmiQ5csiUHn4"
}
},
"required": ["url"]
}
}
}
},
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"description": "Error response",
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
},
"put": {
"summary": "Uploads an object via a presigned URL",
"tags": ["object"],
"parameters": [
{
"schema": {
"type": "string",
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJidWNrZXQyL3B1YmxpYy9zYWRjYXQtdXBsb2FkMjMucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.uBQcXzuvXxfw-9WgzWMBfE_nR3VOgpvfZe032sfLSSk"
},
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJidWNrZXQyL3B1YmxpYy9zYWRjYXQtdXBsb2FkMjMucG5nIiwiaWF0IjoxNjE3NzI2MjczLCJleHAiOjE2MTc3MjcyNzN9.uBQcXzuvXxfw-9WgzWMBfE_nR3VOgpvfZe032sfLSSk",
"in": "query",
"name": "token",
"required": true
},
{
"schema": {
"type": "string",
"example": "avatars"
},
"example": "avatars",
"in": "path",
"name": "bucketName",
"required": true
},
{
"schema": {
"type": "string",
"example": "folder/cat.png"
},
"example": "folder/cat.png",
"in": "path",
"name": "*",
"required": true
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"description": "Successful response",
"type": "object",
"properties": {
"Key": {
"type": "string",
"example": "projectref/avatars/folder/cat.png"
}
},
"required": ["Key"]
}
}
}
},
"4XX": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"description": "Error response",
"type": "object",
"properties": {
"statusCode": {
"type": "string"
},
"error": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["statusCode", "error", "message"],
"title": "errorSchema"
}
}
}
}
}
}
},
"/object/sign/{bucketName}/{wildcard}": {
"post": {
"summary": "Generate a presigned url to retrieve an object",
@@ -1603,6 +1826,9 @@
}
]
},
"version": {
"type": "string"
},
"created_at": {
"anyOf": [
{
@@ -1649,6 +1875,15 @@
"public": {
"type": "boolean"
},
"file_size_limit": {
"type": "integer"
},
"allowed_mime_types": {
"type": ["null", "array"],
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
@@ -1,4 +1,5 @@
import { saveAs } from 'file-saver'
import saveAs from 'file-saver'
import Papa from 'papaparse'
import { useState, ReactNode } from 'react'
import {
Button,
@@ -18,7 +19,6 @@ import SortPopover from './sort'
import RefreshButton from './RefreshButton'
import { confirmAlert } from 'components/to-be-cleaned/ModalsDeprecated/ConfirmModal'
import { Sort, Filter, SupaTable } from 'components/grid/types'
import { exportRowsToCsv } from 'components/grid/utils'
import { useDispatch, useTrackedState } from 'components/grid/store'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { useTableRowDeleteMutation } from 'data/table-rows/table-row-delete-mutation'
@@ -349,8 +349,18 @@ const RowHeader = ({ table, sorts, filters }: RowHeaderProps) => {
const rows = allRowsSelected
? await state.rowService!.fetchAllData(filters, sorts)
: allRows.filter((x) => selectedRows.has(x.idx))
const formattedRows = rows.map((row) => {
const formattedRow = row
Object.keys(row).map((column) => {
if (typeof row[column] === 'object' && row[column] !== null)
formattedRow[column] = JSON.stringify(formattedRow[column])
})
return formattedRow
})
const csv = exportRowsToCsv(state.table!.columns, rows)
const csv = Papa.unparse(formattedRows, {
columns: state.table!.columns.map((column) => column.name),
})
const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
saveAs(csvData, `${state.table!.name}_rows.csv`)
setIsExporting(false)
-29
View File
@@ -1,5 +1,3 @@
import { SupaColumn, SupaRow } from '../types'
export function deepClone(obj: unknown) {
try {
return JSON.parse(JSON.stringify(obj))
@@ -8,33 +6,6 @@ export function deepClone(obj: unknown) {
}
}
export function exportRowsToCsv(columns: SupaColumn[], rows: SupaRow[], separator: string = ',') {
const keys = columns.map((x) => x.name) || []
const csv =
keys.join(separator) +
'\n' +
rows
.map((row) => {
return keys
.map((k) => {
let cell = row[k] === null || row[k] === undefined ? '' : row[k]
cell =
cell instanceof Date
? cell.toLocaleString()
: typeof cell == 'object' || Array.isArray(cell)
? JSON.stringify(cell).replace(/"/g, '""')
: cell.toString().replace(/"/g, '""')
if (cell.search(/("|,|\n)/g) >= 0) {
cell = `"${cell}"`
}
return cell
})
.join(separator)
})
.join('\n')
return csv
}
export function formatClipboardValue(value: any) {
if (value === null) return ''
if (typeof value == 'object' || Array.isArray(value)) {
@@ -92,18 +92,10 @@ const PublicationsList: FC<Props> = ({ onSelectPublication = () => {} }) => {
<Table.th key="header.id" className="hidden lg:table-cell">
System ID
</Table.th>,
<Table.th key="header.insert" className="text-center">
Insert
</Table.th>,
<Table.th key="header.update" className="text-center">
Update
</Table.th>,
<Table.th key="header.delete" className="text-center">
Delete
</Table.th>,
<Table.th key="header.truncate" className="text-center">
Truncate
</Table.th>,
<Table.th key="header.insert">Insert</Table.th>,
<Table.th key="header.update">Update</Table.th>,
<Table.th key="header.delete">Delete</Table.th>,
<Table.th key="header.truncate">Truncate</Table.th>,
<Table.th key="header.source" className="text-right">
Source
</Table.th>,
@@ -118,16 +110,12 @@ const PublicationsList: FC<Props> = ({ onSelectPublication = () => {} }) => {
</Table.td>
{publicationEvents.map((event) => (
<Table.td key={event.key}>
<div className="flex justify-center">
<Toggle
size="tiny"
checked={x[event.key]}
disabled={!canUpdatePublications}
onChange={() =>
toggleListenEvent(x, event.event.toLowerCase(), x[event.key])
}
/>
</div>
<Toggle
size="tiny"
checked={x[event.key]}
disabled={!canUpdatePublications}
onChange={() => toggleListenEvent(x, event.event.toLowerCase(), x[event.key])}
/>
</Table.td>
))}
<Table.td className="px-4 py-3 pr-2">
@@ -11,6 +11,14 @@ const ProjectUsageSection: FC = observer(({}) => {
const { ref: projectRef } = useParams()
const { data: usage, error: usageError, isLoading } = useProjectUsageQuery({ projectRef })
const usageColumns = [
'db_egress',
'storage_egress',
'monthly_active_users',
'realtime_message_count',
'func_invocations',
]
if (usageError) {
return (
<InformationBox
@@ -23,7 +31,7 @@ const ProjectUsageSection: FC = observer(({}) => {
}
const hasProjectData = usage
? Object.keys(usage)
? usageColumns
.map((key) => usage[key as ProjectUsageResponseUsageKeys].usage)
.some((usage) => (usage ?? 0) > 0)
: false
@@ -1070,5 +1070,91 @@ select
'table hit rate' as name,
sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) as ratio
from pg_statio_user_tables;`,
}
},
{
id: 20,
type: 'quickstart',
title: 'OpenAI Vector Search',
description: 'Template for the Next.js OpenAI Doc Search Starter.',
sql: `
-- Enable pg_vector extension
create extension if not exists vector with schema public;
-- Create tables
create table "public"."nods_page" (
id bigserial primary key,
parent_page_id bigint references public.nods_page,
path text not null unique,
checksum text,
meta jsonb,
type text,
source text
);
alter table "public"."nods_page" enable row level security;
create table "public"."nods_page_section" (
id bigserial primary key,
page_id bigint not null references public.nods_page on delete cascade,
content text,
token_count int,
embedding vector(1536),
slug text,
heading text
);
alter table "public"."nods_page_section" enable row level security;
-- Create embedding similarity search functions
create or replace function match_page_sections(embedding vector(1536), match_threshold float, match_count int, min_content_length int)
returns table (id bigint, page_id bigint, slug text, heading text, content text, similarity float)
language plpgsql
as $$
#variable_conflict use_variable
begin
return query
select
nods_page_section.id,
nods_page_section.page_id,
nods_page_section.slug,
nods_page_section.heading,
nods_page_section.content,
(nods_page_section.embedding <#> embedding) * -1 as similarity
from nods_page_section
-- We only care about sections that have a useful amount of content
where length(nods_page_section.content) >= min_content_length
-- The dot product is negative because of a Postgres limitation, so we negate it
and (nods_page_section.embedding <#> embedding) * -1 > match_threshold
-- OpenAI embeddings are normalized to length 1, so
-- cosine similarity and dot product will produce the same results.
-- Using dot product which can be computed slightly faster.
--
-- For the different syntaxes, see https://github.com/pgvector/pgvector
order by nods_page_section.embedding <#> embedding
limit match_count;
end;
$$;
create or replace function get_page_parents(page_id bigint)
returns table (id bigint, parent_page_id bigint, path text, meta jsonb)
language sql
as $$
with recursive chain as (
select *
from nods_page
where id = page_id
union all
select child.*
from nods_page as child
join chain on chain.parent_page_id = child.id
)
select id, parent_page_id, path, meta
from chain;
$$;
`.trim(),
},
]
@@ -175,7 +175,6 @@ export const PgbouncerConfig: FC<ConfigProps> = observer(
ignore_startup_parameters: {
title: 'Ignore Startup Parameters',
type: 'string',
readOnly: true,
help: 'Defaults are either blank or "extra_float_digits"',
},
},
@@ -1,9 +1,10 @@
import { FC } from 'react'
import { observer } from 'mobx-react-lite'
import type { PostgresTable } from '@supabase/postgres-meta'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { checkPermissions, useStore } from 'hooks'
import { checkPermissions, useLocalStorage, useStore } from 'hooks'
import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query'
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
interface Props {
selectedSchema: string
@@ -12,14 +13,33 @@ interface Props {
const EmptyState: FC<Props> = ({ selectedSchema, onAddTable }) => {
const { meta } = useStore()
const tables = meta.tables.list((table: PostgresTable) => table.schema === selectedSchema)
const isProtectedSchema = meta.excludedSchemas.includes(selectedSchema)
const canCreateTables =
!isProtectedSchema && checkPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables')
const [sort] = useLocalStorage<'alphabetical' | 'grouped-alphabetical'>(
'table-editor-sort',
'alphabetical'
)
const { project } = useProjectContext()
const { data } = useEntityTypesQuery(
{
projectRef: project?.ref,
connectionString: project?.connectionString,
schema: selectedSchema,
sort,
},
{
keepPreviousData: true,
}
)
const totalCount = data?.pages?.[0].data.count ?? 0
return (
<div className="w-full h-full flex items-center justify-center">
{tables.length === 0 ? (
{totalCount === 0 ? (
<ProductEmptyState
title="Table Editor"
ctaButtonLabel={canCreateTables ? 'Create a new table' : undefined}
@@ -41,7 +41,7 @@ const GridHeaderActions: FC<Props> = ({
icon={<IconCode size={14} strokeWidth={2} />}
onClick={handlePreviewToggle}
>
API Quickstart
API
</Button>
)
}
@@ -72,9 +72,7 @@ const GridHeaderActions: FC<Props> = ({
</Tooltip.Portal>
</Tooltip.Root>
)}
<div className="mt-[1px]">
<RenderAPIPreviewToggle />
</div>
<Link href={`/project/${projectRef}/auth/policies?search=${table.id}`}>
<a>
<Button
@@ -95,6 +93,9 @@ const GridHeaderActions: FC<Props> = ({
</Button>
</a>
</Link>
<div className="mt-[1px]">
<RenderAPIPreviewToggle />
</div>
</div>
)
}
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more