diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index e22da537402..e394aa54dfe 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -472,6 +472,7 @@ export const auth = { items: [ { name: 'Overview', url: '/guides/auth/auth-helpers' }, { name: 'Auth UI', url: '/guides/auth/auth-helpers/auth-ui' }, + { name: 'Flutter Auth UI', url: '/guides/auth/auth-helpers/flutter-auth-ui' }, { name: 'Next.js', url: '/guides/auth/auth-helpers/nextjs', @@ -526,6 +527,10 @@ export const database: NavMenuConstant = { name: 'Postgres Guides', url: undefined, items: [ + { + name: 'JSON and unstructured data', + url: '/guides/database/json', + }, { name: 'Implementing Full Text Search', url: '/guides/database/full-text-search' }, { name: 'Implementing Cascade Deletes', url: '/guides/database/postgres/cascade-deletes' }, { name: 'Implementing column encryption', url: '/guides/database/column-encryption' }, diff --git a/apps/docs/lib/mdx/generateRefMarkdown.tsx b/apps/docs/lib/mdx/generateRefMarkdown.tsx index 790591280f7..6e71c0c2660 100644 --- a/apps/docs/lib/mdx/generateRefMarkdown.tsx +++ b/apps/docs/lib/mdx/generateRefMarkdown.tsx @@ -3,7 +3,7 @@ import fs from 'fs' import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' import matter from 'gray-matter' import { serialize } from 'next-mdx-remote/serialize' -import codeHikeTheme from '~/code-hike.theme.json' assert { type: 'json' } +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } import { ICommonMarkdown } from '~/components/reference/Reference.types' async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) { diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index d6f21fa8b8b..682af108190 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -8,7 +8,7 @@ import withTM from 'next-transpile-modules' import withYaml from 'next-plugin-yaml' import configureBundleAnalyzer from '@next/bundle-analyzer' -import codeHikeTheme from './code-hike.theme.json' assert { type: 'json' } +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } const withBundleAnalyzer = configureBundleAnalyzer({ enabled: process.env.ANALYZE === 'true', @@ -103,7 +103,15 @@ const nextConfig = { const configExport = () => { const plugins = [ - withTM(['ui', 'common', '@supabase/auth-helpers-nextjs', 'mermaid', 'mdx-mermaid', 'dayjs']), + withTM([ + 'ui', + 'common', + '@supabase/auth-helpers-nextjs', + 'mermaid', + 'mdx-mermaid', + 'dayjs', + 'shared-data', + ]), withMDX, withYaml, withBundleAnalyzer, diff --git a/apps/docs/pages/_app.tsx b/apps/docs/pages/_app.tsx index 2132434d66b..229131db7da 100644 --- a/apps/docs/pages/_app.tsx +++ b/apps/docs/pages/_app.tsx @@ -1,7 +1,7 @@ import '../../../packages/ui/build/css/themes/light.css' import '../../../packages/ui/build/css/themes/dark.css' -import '../styles/code-hike.scss' +import 'config/code-hike.scss' import '../styles/main.scss?v=1.0.0' import '../styles/new-docs.scss' import '../styles/prism-okaidia.scss' diff --git a/apps/docs/pages/guides/ai.mdx b/apps/docs/pages/guides/ai.mdx index c7df810f3fc..2153bdde029 100644 --- a/apps/docs/pages/guides/ai.mdx +++ b/apps/docs/pages/guides/ai.mdx @@ -124,6 +124,12 @@ export const integrations = [ export const customers = [ + { + name: 'Berri AI Boosts Productivity by Migrating from AWS RDS to Supabase with pgvector', + description: + 'Learn how Berri AI overcame challenges with self-hosting their vector database on AWS RDS and successfully migrated to Supabase.', + href: 'https://supabase.com/customers/berriai', + }, { name: 'Mendable switches from Pinecone to Supabase for PostgreSQL vector embeddings', description: diff --git a/apps/docs/pages/guides/ai/examples/nextjs-vector-search.mdx b/apps/docs/pages/guides/ai/examples/nextjs-vector-search.mdx index 01bef30379e..b340a6607b6 100644 --- a/apps/docs/pages/guides/ai/examples/nextjs-vector-search.mdx +++ b/apps/docs/pages/guides/ai/examples/nextjs-vector-search.mdx @@ -284,7 +284,7 @@ With our database set up, we need to process and store all `.mdx` files in the ` - ```txt + ```bash NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= diff --git a/apps/docs/pages/guides/ai/python/[slug].tsx b/apps/docs/pages/guides/ai/python/[slug].tsx index b52312424d7..fcbd53160c0 100644 --- a/apps/docs/pages/guides/ai/python/[slug].tsx +++ b/apps/docs/pages/guides/ai/python/[slug].tsx @@ -5,7 +5,7 @@ import { serialize } from 'next-mdx-remote/serialize' import { relative } from 'path' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' -import codeHikeTheme from '~/code-hike.theme.json' assert { type: 'json' } +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } import components from '~/components' import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' diff --git a/apps/docs/pages/guides/auth/auth-helpers.mdx b/apps/docs/pages/guides/auth/auth-helpers.mdx index b9573fd1609..26b798b820b 100644 --- a/apps/docs/pages/guides/auth/auth-helpers.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers.mdx @@ -19,6 +19,14 @@ A collection of framework-specific Auth utilities for working with Supabase. description={'A pre-built React component for authenticating users.'} /> + {/* Flutter Auth UI */} +
+ +
{/* Next.js */}
+ +## Add Flutter Auth UI + +Add the latest version of the package [supabase-auth-ui](https://pub.dev/packages/supabase_auth_ui) to pubspec.yaml: + +```yaml +dependencies: + flutter: + sdk: flutter + supabase_auth_ui: ^0.1.0+2 +``` + +### Initialize the Flutter Auth Package + +```dart +import 'package:flutter/material.dart'; +import 'package:supabase_auth_ui/supabase_auth_ui.dart'; + +void main() async { + await Supabase.initialize( + url: dotenv.get('SUPABASE_URL'), + anonKey: dotenv.get('SUPABASE_ANON_KEY'), + ); + + runApp(const MyApp()); +} +``` + +### Email Auth + +Use a SupaEmailAuth widget to create an email and password signin and signup form. It also contains a button to toggle to display a forgot password form. + +You can pass metadataFields to add additional fields to the form to pass as metadata to Supabase. + +```dart +SupaEmailAuth( + redirectTo: kIsWeb ? null : 'io.mydomain.myapp://callback', + onSignInComplete: (response) {}, + onSignUpComplete: (response) {}, + metadataFields: [ + MetaDataField( + prefixIcon: const Icon(Icons.person), + label: 'Username', + key: 'username', + validator: (val) { + if (val == null || val.isEmpty) { + return 'Please enter something'; + } + return null; + }, + ), + ], +) +``` + +### Magic Link Auth + +Use SupaMagicAuth widget to create a magic link signIn form. + +```dart +SupaMagicAuth( + redirectUrl: kIsWeb ? null : 'io.mydomain.myapp://callback', + onSuccess: (Session response) {}, + onError: (error) {}, +) +``` + +### Reset password + +Use SupaResetPassword to create a password reset form. + +```dart +SupaResetPassword( + accessToken: supabase.auth.currentSession?.accessToken, + onSuccess: (UserResponse response) {}, + onError: (error) {}, +) +``` + +### Phone Auth + +Use SupaPhoneAuth to create a phone authentication form. + +```dart +SupaPhoneAuth( + authAction: SupaAuthAction.signUp, + onSuccess: (AuthResponse response) {}, + ), +``` + +### Social Auth + +The package supports login with [official social providers](../../auth#providers). + +Use SupaSocialsAuth to create list of social login buttons. + +```dart +SupaSocialsAuth( + socialProviders: [ + SocialProviders.apple, + SocialProviders.google, + ], + colored: true, + redirectUrl: kIsWeb + ? null + : 'io.mydomain.myapp://callback', + onSuccess: (Session response) {}, + onError: (error) {}, +) +``` + +### Theming + +This package uses plain Flutter components allowing you to control the appearance of the components using your own theme. + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index d783f804feb..f8ded004290 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -10,6 +10,15 @@ export const meta = { The [Next.js Auth Helpers package](https://github.com/supabase/auth-helpers) configures Supabase Auth to store the user's `session` in a `cookie`, rather than `localStorage`. This makes it available across the client and server of the App Router - [Client Components](/docs/guides/auth/auth-helpers/nextjs#client-components), [Server Components](/docs/guides/auth/auth-helpers/nextjs#server-components), [Server Actions](/docs/guides/auth/auth-helpers/nextjs#server-actions), [Route Handlers](/docs/guides/auth/auth-helpers/nextjs#route-handlers) and [Middleware](/docs/guides/auth/auth-helpers/nextjs#middleware). The `session` is automatically sent along with any requests to Supabase. +
+ +
+ > Note: If you are using the `pages` directory, check out [Auth Helpers in Next.js Pages Directory](/docs/guides/auth/auth-helpers/nextjs-pages). ## Configuration @@ -170,6 +179,15 @@ export async function GET(request: NextRequest) { ## Authentication +
+ +
+ Authentication can be initiated [client](/docs/guides/auth/auth-helpers/nextjs#client-side) or [server-side](/docs/guides/auth/auth-helpers/nextjs#server-side). All of the [supabase-js authentication strategies](/docs/reference/javascript/auth-api) are supported with the Auth Helpers client. > Note: The authentication flow requires the [Code Exchange Route](/docs/guides/auth/auth-helpers/nextjs#code-exchange-route) to exchange a `code` for the user's `session`. @@ -446,6 +464,15 @@ export default async function Login() { ### Client Component +
+ +
+ [Client Components](https://nextjs.org/docs/getting-started/react-essentials#client-components) allow the use of client-side hooks - such as `useEffect` and `useState`. They can be used to request data from Supabase client-side, and [subscribe to realtime events](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs/app/realtime-posts.tsx). + +
+ [Server Components](https://nextjs.org/docs/getting-started/react-essentials#server-components) allow for asynchronous data to be fetched server-side. > Note: In order to use Supabase in Server Components, you need to have implemented the [Middleware](/docs/guides/auth/auth-helpers/nextjs#refresh-session-with-middleware) steps above. @@ -580,6 +616,15 @@ export default async function ServerComponent() { ### Server Action +
+ +
+ [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions) allow mutations to be performed server-side. > Note: Server Actions are currently in `alpha` so may change without notice. @@ -651,6 +696,15 @@ export default async function NewTodo() { ### Route Handler +
+ +
+ [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) replace API Routes and allow for logic to be performed server-side. They can respond to `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, and `OPTIONS` requests. - - -1. Go to the [Table Editor](https://app.supabase.com/project/_/editor) page in the Dashboard. -2. Click **New Table** and create a table called `books`. -3. Include a primary key with the following properties: - - Name: `id` - - Type: `int8` - - Default value: `Automatically generate as indentity` -4. Click **Save**. -5. Click **New Column** and add 3 columns with the following properties: - - **title** column - - Name: `title` - - Type: `text` - - **author** column - - Name: `author` - - Type: `text` - - **metadata** column - - Name: `metadata` - - Type: `jsonb` - - ```sql @@ -52,32 +43,39 @@ create table books ( ); ``` + + + +1. Go to the [Table Editor](https://app.supabase.com/project/_/editor) page in the Dashboard. +2. Click **New Table** and create a table called `books`. +3. Include a primary key with the following properties and click save: + +- Name: `id` + - Type: `int8` + - Default value: `Automatically generate as indentity` +- **title** column + - Name: `title` + - Type: `text` +- **author** column + - Name: `author` + - Type: `text` +- **metadata** column + - Name: `metadata` + - Type: `jsonb` + -## Insert data into the table +## Inserting JSON data + +You can insert JSON data in the same way that you insert any other data. The data must be valid JSON. - - -1. Go to the [Table Editor](https://app.supabase.com/project/_/editor) page in the Dashboard. -2. Select the `books` table in the sidebar. -3. Click **+ Insert row** and add 5 rows with the following properties: - -| id | title | author | metadata | -| --- | ----------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------- | -| 1 | The Poky Little Puppy | Janette Sebring Lowrey | `json {"ages":[3,6],"price":5.95,"description":"Puppy is slower than other, bigger animals."}` | -| 2 | The Tale of Peter Rabbit | Beatrix Potter | `json {"ages":[2,5],"price":4.49,"description":"Rabbit eats some vegetables."}` | -| 3 | Tootle | Gertrude Crampton | `json {"ages":[2,5],"price":3.99,"description":"Little toy train has big dreams."}` | -| 4 | Green Eggs and Ham | Dr. Seuss | `json {"ages":[4,8],"price":7.49,"description":"Sam has changing food preferences and eats unusually colored food."}` | -| 5 | Harry Potter and the Goblet of Fire | J.K. Rowling | `json {"ages":[10,99],"price":24.95,"description":"Fourth year of school starts, big drama ensues."}` | - - ```sql @@ -111,6 +109,21 @@ values ); ``` + + + +1. Go to the [Table Editor](https://app.supabase.com/project/_/editor) page in the Dashboard. +2. Select the `books` table in the sidebar. +3. Click **+ Insert row** and add 5 rows with the following properties: + +| id | title | author | metadata | +| --- | ----------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------- | +| 1 | The Poky Little Puppy | Janette Sebring Lowrey | `json {"ages":[3,6],"price":5.95,"description":"Puppy is slower than other, bigger animals."}` | +| 2 | The Tale of Peter Rabbit | Beatrix Potter | `json {"ages":[2,5],"price":4.49,"description":"Rabbit eats some vegetables."}` | +| 3 | Tootle | Gertrude Crampton | `json {"ages":[2,5],"price":3.99,"description":"Little toy train has big dreams."}` | +| 4 | Green Eggs and Ham | Dr. Seuss | `json {"ages":[4,8],"price":7.49,"description":"Sam has changing food preferences and eats unusually colored food."}` | +| 5 | Harry Potter and the Goblet of Fire | J.K. Rowling | `json {"ages":[10,99],"price":24.95,"description":"Fourth year of school starts, big drama ensues."}` | + @@ -167,48 +180,11 @@ const { data, error } = await supabase.from('books').insert([ -## View the data +## Query JSON data - - +Querying JSON data is similar to querying other data, with a few other features to access nested values. -```sql -select * -from books; -``` - - - - -```js -const { data, error } = await supabase.from('books').select('*') -console.log(JSON.stringify(data, null, 2)) -``` - - - - -| id | title | author | metadata | -| --- | ----------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------- | -| 1 | The Poky Little Puppy | Janette Sebring Lowrey | `json{"ages":[3,6],"price":5.95,"description":"Puppy is slower than other, bigger animals."}` | -| 2 | The Tale of Peter Rabbit | Beatrix Potter | `json{"ages":[2,5],"price":4.49,"description":"Rabbit eats some vegetables."} ` | -| 3 | Tootle | Gertrude Crampton | `json{"ages":[2,5],"price":3.99,"description":"Little toy train has big dreams."} ` | -| 4 | Green Eggs and Ham | Dr. Seuss | `json{"ages":[4,8],"price":7.49,"description":"Sam has changing food preferences and eats unusually colored food."} ` | -| 5 | Harry Potter and the Goblet of Fire | J.K. Rowling | `json{"ages":[10,99],"price":24.95,"description":"Fourth year of school starts, big drama ensues."} ` | - -The data as it appears here has the `JSONB` fields in a different order than when inserted. As mentioned earlier, data is parsed as its inserted when using the JSONB format. - - - - -## Query the `JSONB` data - -Select the title, description, price, and age range for each book. +Postgres support a range of [JSON functions and operators](https://www.postgresql.org/docs/current/functions-json.html). For example, the `->` operator returns values as `jsonb` data. If you want the data returned as `text`, use the `->>` operator. 'description' as description, + metadata ->> 'description' as description, -- returned as text metadata -> 'price' as price, metadata -> 'ages' -> 0 as low_age, metadata -> 'ages' -> 1 as high_age @@ -232,12 +208,13 @@ from books; ```js -const { data, error } = await supabase - .from('books') - .select( - 'title,description:metadata->description,price:metadata->price,low_age:metadata->ages->0,high_age:metadata->ages->1' - ) -console.log(JSON.stringify(data, null, 2)) +const { data, error } = await supabase.from('books').select(` + title, + description: metadata->description, + price: metadata->price, + low_age: metadata->ages->0, + high_age: metadata->ages->1 + `) ``` @@ -254,16 +231,42 @@ console.log(JSON.stringify(data, null, 2)) -Note that the `->` operator returns JSONB data. If you want TEXT/STRING data returned, use the `->>` operator. +## Validating JSON data -- metadata -> 'description' (returns a JSON object) -- metadata ->> 'description' (returns STRING/TEXT data) +Supabase provides the [`pg_jsonschema` extension](/docs/guides/database/extensions/pg_jsonschema) that adds the ability to validate `json` and `jsonb` data types against [JSON Schema](https://json-schema.org/) documents. + +Once you have enabled the extension, you can add a "check constraint" to your table to validate the JSON data: + +```sql +create table customers ( + id serial primary key, + metadata json +); + +alter table customers +add constriant check_metadata check ( + json_matches_schema( + '{ + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string", + "maxLength": 16 + } + } + } + }', + metadata + ) +); +``` ## Resources -- [Supabase JS Client](https://github.com/supabase/supabase-js) -- [PostgreSQL: JSON Functions and Operators](https://www.postgresql.org/docs/12/functions-json.html) -- [PostgreSQL JSON types](https://www.postgresql.org/docs/12/datatype-json.html) +- [Postgres: JSON Functions and Operators](https://www.postgresql.org/docs/current/functions-json.html) +- [Postgres JSON types](https://www.postgresql.org/docs/current/datatype-json.html) export const Page = ({ children }) => diff --git a/apps/docs/pages/guides/database/vault.mdx b/apps/docs/pages/guides/database/vault.mdx index 0d32b241104..3ac5bf84ce3 100644 --- a/apps/docs/pages/guides/database/vault.mdx +++ b/apps/docs/pages/guides/database/vault.mdx @@ -233,30 +233,26 @@ To encrypt data, you need a _key id_. You can use the default key id created aut Both `vault.create_secret()` and `vault.update_secret()` take an optional fourth `new_key_id` argument. This argument can be used to store a different key id for the secret instead of the default value. +{/* prettier-ignore */} ```sql -postgres=> select vault.create_secret('another_s3kre3t_key', 'another_unique_name', - 'This is another description', (pgsodium.create_key()).id); +select vault.create_secret( + 'another_s3kre3t_key', + 'another_unique_name', + 'This is another description', + (pgsodium.create_key()).id +); +``` + +Result: + +```sh -[ RECORD 1 ]-+------------------------------------- create_secret | cec9e005-a44d-4b19-86e1-febf3cd40619 ``` Which roles should have access to the `vault.secrets` table should be carefully considered. There are two ways to grant access, the first is that the `postgres` user can explicitly grant access to the vault table itself. -## Turning off Statement Logging - -When you insert secrets into the vault table with an INSERT statement, those statements get logged by default into the Supabase logs. Since this would mean your secrets are stored unencrypted in the logs, you should turn off statement logging while using the Vault. - -While turning off statement logging does hinder you if you're used to looking at the logs to debug your application, it provides a much higher level of security by ensuring that your data does not leak out of the database and into the logs. This is especially critical with encrypted column data, because the statement logs will contain the _unencrypted_ secrets. If you _must_ store that data encrypted, then you _must_ turn off statement logging. - -```sql -alter system set statement_log = 'none'; -``` - -And then restart your project from the dashboard to enable that change. - -In the future we are researching various ways to refine the way statement logging interacts with sensitive columns. - -## Resources +### Resources - Read more about Supabase Vault in the [blog post](https://supabase.com/blog/vault-now-in-beta) - [Supabase Vault on GitHub](https://github.com/supabase/vault) diff --git a/apps/docs/pages/guides/functions/kysely-postgres.mdx b/apps/docs/pages/guides/functions/kysely-postgres.mdx index e343a16f89b..765946a81ef 100644 --- a/apps/docs/pages/guides/functions/kysely-postgres.mdx +++ b/apps/docs/pages/guides/functions/kysely-postgres.mdx @@ -26,7 +26,7 @@ Find the example on [GitHub](https://github.com/supabase/supabase/tree/master/ex Get your database connection credentials from your [Supabase Dashboard](https://app.supabase.com/project/_/settings/database) and store them in an `.env` file: -```txt .env +```bash .env DB_HOSTNAME= DB_PASSWORD= DB_SSL_CERT="-----BEGIN CERTIFICATE----- diff --git a/apps/docs/pages/guides/functions/quickstart.mdx b/apps/docs/pages/guides/functions/quickstart.mdx index a01448526ab..235556c439e 100644 --- a/apps/docs/pages/guides/functions/quickstart.mdx +++ b/apps/docs/pages/guides/functions/quickstart.mdx @@ -132,7 +132,7 @@ In a given workspace (or workspace folder), sub-paths can be enabled for Deno, w For example if you have a project like this: -```txt +``` project ├── app └── supabase @@ -201,7 +201,7 @@ For use-cases which require low-latency we recommend [Edge Functions](/docs/guid We recommend developing “fat functions”. This means that you should develop few large functions, rather than many small functions. One common pattern when developing Functions is that you need to share code between two or more Functions. To do this, you can store any shared code in a folder prefixed with an underscore (`_`). We recommend this folder structure: -```txt +```bash └── supabase ├── functions │ ├── import_map.json # A top-level import map to use across functions. diff --git a/apps/docs/pages/guides/getting-started/tutorials/with-nextjs.mdx b/apps/docs/pages/guides/getting-started/tutorials/with-nextjs.mdx index ecfa0af0cbe..97c85a609dc 100644 --- a/apps/docs/pages/guides/getting-started/tutorials/with-nextjs.mdx +++ b/apps/docs/pages/guides/getting-started/tutorials/with-nextjs.mdx @@ -62,8 +62,8 @@ NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY ``` -And one optional step is to update the CSS file `styles/globals.css` to make the app look nice. -You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/nextjs-ts-user-management/styles/globals.css). +And one optional step is to update the CSS file `app/globals.css` to make the app look nice. +You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/nextjs-user-management/app/globals.css). ### Supabase Auth Helpers @@ -241,6 +241,12 @@ export default function AuthForm() { + + + +If you are using TypeScript for this project, see [generating types](/docs/guides/api/rest/generating-types) to automatically generate types from your database tables. + + Add the `AuthForm` component to your home page diff --git a/apps/docs/pages/guides/getting-started/tutorials/with-sveltekit.mdx b/apps/docs/pages/guides/getting-started/tutorials/with-sveltekit.mdx index ca9ce871676..aa330f7154c 100644 --- a/apps/docs/pages/guides/getting-started/tutorials/with-sveltekit.mdx +++ b/apps/docs/pages/guides/getting-started/tutorials/with-sveltekit.mdx @@ -44,7 +44,7 @@ PUBLIC_SUPABASE_URL="YOUR_SUPABASE_URL" PUBLIC_SUPABASE_ANON_KEY="YOUR_SUPABASE_KEY" ``` -Optionally, add `src/styles.css` with the [CSS from the example](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/svelte-user-management/src/app.css). +Optionally, add `src/styles.css` with the [CSS from the example](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/sveltekit-user-management/src/styles.css). ### Supabase Auth Helpers diff --git a/apps/docs/pages/guides/integrations/picket.mdx b/apps/docs/pages/guides/integrations/picket.mdx index 0508e5cfa18..55f7c755e57 100644 --- a/apps/docs/pages/guides/integrations/picket.mdx +++ b/apps/docs/pages/guides/integrations/picket.mdx @@ -97,7 +97,7 @@ Create a `.env.local` file and enter the following values - `NEXT_PUBLIC_SUPABASE_ANON_KEY` => You can find this project API key under "Settings > API" in your Supabase project - `SUAPBASE_JWT_SECRET`=> You can find this secret under "Settings > API" in your Supabase project -```txt +```bash NEXT_PUBLIC_PICKET_PUBLISHABLE_KEY="YOUR_PICKET_PUBLISHABLE_KEY" PICKET_PROJECT_SECRET_KEY="YOUR_PICKET_PROJECT_SECRET_KEY" NEXT_PUBLIC_SUPABASE_URL="YOUR_SUPABASE_URL" diff --git a/apps/docs/pages/guides/integrations/prisma.mdx b/apps/docs/pages/guides/integrations/prisma.mdx index b8b07e3c038..0aba729806b 100644 --- a/apps/docs/pages/guides/integrations/prisma.mdx +++ b/apps/docs/pages/guides/integrations/prisma.mdx @@ -68,8 +68,7 @@ touch .env In the `.env` file, add a `DATABASE_URL` variable and add the connection string from **step 1**. The `.env` file should look like: -```env -# .env +```bash .env DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres" ``` @@ -147,13 +146,12 @@ Append the `?pgbouncer=true` flag to the `DATABASE_URL` variable. Your `.env` file should resemble the following: -```env -# .env +```bash .env # PostgreSQL connection string used for migrations DIRECT_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres" + # PostgreSQL connection string with pgBouncer config — used by Prisma Client DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:6543/postgres?pgbouncer=true" - ``` Update your Prisma schema by setting the `directUrl` in the datasource block: diff --git a/apps/docs/styles/main.scss b/apps/docs/styles/main.scss index ce93b3296a2..d6b1d9cc720 100644 --- a/apps/docs/styles/main.scss +++ b/apps/docs/styles/main.scss @@ -32,7 +32,7 @@ body { } ::selection { - background-color: #6ee7b7; + background-color: #6ee7b7 !important; color: #333 !important; } diff --git a/apps/www/_blog/2022-08-19-supabase-vault.mdx b/apps/www/_blog/2022-08-19-supabase-vault.mdx index 4415e4823eb..d635b36ffb9 100644 --- a/apps/www/_blog/2022-08-19-supabase-vault.mdx +++ b/apps/www/_blog/2022-08-19-supabase-vault.mdx @@ -10,14 +10,19 @@ date: '2022-08-19' toc_depth: 2 --- -Today we're announcing [Supabase Vault](https://github.com/supabase/vault), a Postgres extension for managing secrets and encryption inside your database. +Today we're announcing [Supabase Vault](https://supabase.com/docs/guides/database/vault), a Postgres extension for managing secrets and encryption inside your database. Vault is a thin usability-layer on top of [pgsodium](https://github.com/michelp/pgsodium). -Vault is not available on the Supabase platform yet. We're finalizing usability and security testing. -This release is intended to gather user-feedback from our community and customers. +
-Soon, we'll release a blog post that describes more about the technology behind Vault - [libsodium](https://doc.libsodium.org/) and -[pgsodium](https://doc.libsodium.org/). For now, we will go through a quick example of storing a secret, like a service access token, into the Vault. +❇️ UPDATE JUNE 2023 ❇️ + +Vault is now available on every Supabase project. [Check it out](https://app.supabase.com/project/_/settings/vault/secrets) + +
+ +[Transparent Column Encryption with Postgres](https://supabase.com/blog/transparent-column-encryption-with-postgres) is a blog post that describes the technology behind Vault - [libsodium](https://doc.libsodium.org/) and +[pgsodium](https://doc.libsodium.org/). Now, we will go through a quick example of storing a secret, like a service access token, into the Vault. ## Background @@ -179,4 +184,4 @@ optionally creating new keys, and select them from the view when you want to use The Vault is good for a reasonable amount of secure data, like API keys, access tokens, or environment variables. But if you have a lot more sensitive information, like personally Identifiable Information (PII), you may want to break them out into side-tables using pgsodium's -[Transparent Column Encryption](https://github.com/michelp/pgsodium#transparent-column-encryption) which we will describe soon in a follow-up blog post. Stay tuned! +[Transparent Column Encryption](https://supabase.com/blog/transparent-column-encryption-with-postgres) which we will describe soon in a follow-up blog post. Stay tuned! diff --git a/apps/www/_blog/2022-12-01-transparent-column-encryption-with-postgres.mdx b/apps/www/_blog/2022-12-01-transparent-column-encryption-with-postgres.mdx index be6c55497fd..7e8a4d1adc4 100644 --- a/apps/www/_blog/2022-12-01-transparent-column-encryption-with-postgres.mdx +++ b/apps/www/_blog/2022-12-01-transparent-column-encryption-with-postgres.mdx @@ -17,9 +17,9 @@ pgsodium's Transparent Column Encryption (TCE) is one of the safest ways, and ca To understand how TCE works, let's first do a deep-dive into an important encryption topic: key derivation. -
+
-This post is a sneak peek of a big feature we are shipping on LW6. To not miss a thing, get your ticket for [Supabase Launch Week 6!](https://supabase.com/launch-week). +👀 Transparent Column Encryption (TCE) is the foundational feature of the Supabase Vault, a safe and easy way to store encrypted secrets and other data in your Postgres database. [Learn more about Supabase Vault](https://supabase.com/docs/guides/database/vault)
diff --git a/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx index 4f807e2ceba..ef7a62d1640 100644 --- a/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx +++ b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx @@ -18,6 +18,14 @@ During our last Launch Week we [announced](/blog/supabase-vault) Supabase Vault Vault is a new Postgres extension and accompanying Supabase UI that makes it safe and easy to store encrypted secrets and encrypt other stored data in your database. This foundation opens up a lot of possibilities for Postgres that go beyond what is available in a stock distribution. From a product perspective we're grouping various features under the “Vault banner”. Let's explore a few of these features. +
+ +❇️ UPDATE JUNE 2023 ❇️ + +Supabase Vault is now available on every Supabase project. [Check it out](https://app.supabase.com/project/_/settings/vault/secrets) + +
+ ## Secrets Management Practically speaking, the Vault is a table of Secrets and Encryption Keys that are stored using [Authenticated Encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) on disk, but available in decrypted form through a Postgres view so that the secrets can be used by applications from SQL. Because the secrets are stored encrypted and authenticated, any backups or replication streams also preserve this encryption in a way that can't be forged. @@ -81,7 +89,7 @@ Privacy is becoming one of the most important features in a modern product. Supa ### Using the Vault -You'll see the Vault appear in the Dashboard over the next month. If you want to use Vault today, email growth@supabase.com and we'll enable it on your account. Vault is available for all customers (including the Free-plan). +To learn how to use Supabase Vault, check out the [docs](https://supabase.com/docs/guides/database/vault). Supabase Vault is now available on all [Supabase projects](https://app.supabase.com/project/_/settings/vault/secrets) (some projects will have to enable via request). ## More Launch Week 6 diff --git a/apps/www/_customers/berriai.mdx b/apps/www/_customers/berriai.mdx new file mode 100644 index 00000000000..4f6cc7e97d0 --- /dev/null +++ b/apps/www/_customers/berriai.mdx @@ -0,0 +1,88 @@ +--- +name: Berri AI +title: Berri AI Boosts Productivity by Migrating from AWS RDS to Supabase with pgvector +# Use meta_title to add a custom meta title. Otherwise it defaults to '{name} | Supabase Customer Stories': +# meta_title: +description: Learn how Berri AI overcame challenges with self-hosting their vector database on AWS RDS and successfully migrated to Supabase. +# Use meta_description to add a custom meta description. Otherwise it defaults to {description}: +meta_description: Learn how Berri AI overcame challenges with self-hosting their vector database on AWS RDS and successfully migrated to Supabase. +author: paul_copplestone +author_title: Supabase +author_url: https://github.com/kiwicopple +author_image_url: https://avatars2.githubusercontent.com/u/10214025?s=400&u=c6775be2ae667e2acae3ccd347fed62bb3f5b3e7&v=4 +authorURL: https://github.com/kiwicopple +logo: /images/customers/logos/berriai.png +logo_inverse: /images/customers/logos/light/berriai.png +og_image: /images/customers/og/berriai.jpg +tags: + - supabase +date: '2023-06-06' +company_url: 'https://www.berri.ai/' +stats: + [ + { stat: '00,000', label: Example stat }, + { stat: '00,000', label: Example stat }, + { stat: '00,000', label: Example stat }, + ] +misc: [{ label: 'Backed by', text: 'Y Combinator' }] +about: Supercharge your products with the power of LLMs like ChatGPT & go from prototype to production in less than a week. +--- + +Berri AI is an API for businesses to programmatically create custom ChatGPT instances on their data. Their customers build production-ready ChatGPT Apps in minutes with features such as prebuilt flows, editable options, authentication, and logging. + +## The Challenge + +Initially, Berri AI attempted to develop with AWS RDS to reduce latency and gain more control over their infrastructure. However, they encountered various challenges, including development cycles, difficulties debugging errors, limited accessibility for non-database team members, and the complexity of managing connection pools and rollbacks. These issues hindered their ability to make changes quickly and impacted their overall productivity. + + + The Python SDK simplified the process for me as a non-database person, empowering me to make + changes and bug fixes. This significantly improved our update velocity, which had a huge impact on + our productivity. + + +## Why they chose Supabase: + +Berri AI migrated their vector database from AWS RDS to Supabase for several compelling reasons. + +1. **Community:** After considering alternatives like pgvector, Pinecone, and Chroma, they prioritized a solution with a strong and accessible community, along with managed infrastructure. +2. **Fewer services to manage:** Since they were already utilizing Supabase for other purposes, it made sense for Berri AI to consolidate their systems and avoid the complexities of self-hosting. One of the major pain points they faced with their previous setup was managing connection pools and handling errors with the Postgres database hosted on AWS. This involved writing extensive code and dealing with rollbacks, with each database update function requiring 40-50 lines of code. Supabase simplified this process significantly by condensing it to just one line of code, eliminating the burdens of managing dependencies and handling new errors. This significantly improved their update velocity, which had a huge impact on their productivity. +3. **Better tooling:** Berri AI experienced frustration with pg_admin. Supabase's user-friendly interface offered a seamless and efficient way to manage and read tables, eliminating the need for pg_admin and providing a simple alternative. This streamlined their workflow and saved valuable time and effort. The accessibility of Supabase's client SDKs and intuitive interface played a crucial role in their decision as well. Team members who were not database experts found it easy to navigate and make changes, reducing reliance on specialized expertise and improving their overall workflow. +4. **Simplicity:** Supabase provides the ability to add new columns in a no-code manner, which provided flexibility and agility in responding to evolving requirements. This feature empowered the team to make on-the-fly adjustments and meet their immediate needs effectively. +5. **Flexibility:** Berri AI also appreciated Supabase's flexibility in allowing them to choose their preferred embedding method, as it was not tied to a specific embedding model. This ensured compatibility and adaptability for their specific use case. + +The integration of pgvector on Supabase, which facilitated efficient storage and retrieval of vectors, proved to be a significant advantage for Berri AI's operations. + + + Switching to Supabase was a game-changer for us. The faster view times allowed me to quickly + access and debug data, enhancing my ability to analyze individual customer issues. The no-code + option to add new columns on the fly was fantastic, enabling us to adapt swiftly. + + +## What They Built + +Berri AI built a platform that enables developers to create and manage custom ChatGPT instances for each individual user, integrating seamlessly with their unique data. + +With Berri AI, businesses can rapidly scale the power of ChatGPT to cater to the needs of every user. The platform provides an out-of-the-box solution for managing a fleet of ChatGPT instances, offering businesses the ability to deliver personalized responses to user queries. This includes answering specific questions related to order status, monthly revenue, or generating personalized learning experiences in the education technology (EdTech) sector, such as summarizing lecture slides or generating practice questions from textbooks. + +The platform's integration with Supabase and pgvector empowers businesses to unlock the full potential of ChatGPT and deliver customized solutions for a wide range of use cases. + + + With Supabase, my life has become much easier. Previously, managing connection pools and dealing + with errors in the Postgres database hosted on AWS was a constant challenge. I had to write 40-50 + lines of code for each function, handle rollbacks, and struggle with dependencies and errors. But + with Supabase, updating the database is now just one line of code. I no longer need to deal with + complex dependencies and obscure errors. Additionally, the frustration of using pgadmin is gone. + Supabase provides a simple UI that allows me to effortlessly manage and interact with my tables. + + +## The Results + +Berri AI achieved significant improvements in their operations by choosing Supabase with pgvector. They experienced streamlined database management, increased update velocity, and improved efficiency in accessing and debugging data. The user-friendly interface and flexibility of Supabase empowered non-experts within the team and facilitated agile adaptations to changing requirements. Overall, this decision transformed their workflow, enhancing productivity and positioning Berri AI for continued success and growth. + +## Tech stack + +- Supabase +- Zeet +- AWS +- OpenAI +- Hugging Face diff --git a/apps/www/code-hike.d.ts b/apps/www/code-hike.d.ts new file mode 100644 index 00000000000..5d2ca4d54d0 --- /dev/null +++ b/apps/www/code-hike.d.ts @@ -0,0 +1,6 @@ +import { remarkCodeHike } from '@code-hike/mdx' + +declare module '@code-hike/mdx' { + export type CodeHikeRemarkPlugin = typeof remarkCodeHike + export type CodeHikeConfig = Parameters[0] +} diff --git a/apps/www/components/Pricing/ComputePricingModal.tsx b/apps/www/components/Pricing/ComputePricingModal.tsx index c7bbf0e164f..eb76e04349b 100644 --- a/apps/www/components/Pricing/ComputePricingModal.tsx +++ b/apps/www/components/Pricing/ComputePricingModal.tsx @@ -88,9 +88,9 @@ export default function ComputePricingModal({ showComputeModal, setShowComputeMo {column.key === 'dedicated' ? ( column.value ? ( - + ) : ( - + ) ) : ( column.value @@ -124,9 +124,9 @@ export default function ComputePricingModal({ showComputeModal, setShowComputeMo > {column.key === 'dedicated' ? ( column.value ? ( - + ) : ( - + ) ) : ( column.value diff --git a/apps/www/components/Pricing/PricingIcons.tsx b/apps/www/components/Pricing/PricingIcons.tsx index 5dd4c804921..223a92a59df 100644 --- a/apps/www/components/Pricing/PricingIcons.tsx +++ b/apps/www/components/Pricing/PricingIcons.tsx @@ -12,7 +12,7 @@ export const Check = () => ( export const IconPricingIncludedCheck = (props: any) => ( - Included in {props.tier} + Included in {props.plan} ) @@ -32,7 +32,7 @@ export const IconPricingMinus = (props: any) => ( clipRule="evenodd" /> - Not included in {props.tier} + Not included in {props.plan} ) diff --git a/apps/www/components/Pricing/PricingTableRow.tsx b/apps/www/components/Pricing/PricingTableRow.tsx index 135b21f3b5b..af3f8d6280c 100644 --- a/apps/www/components/Pricing/PricingTableRow.tsx +++ b/apps/www/components/Pricing/PricingTableRow.tsx @@ -48,35 +48,35 @@ export const PricingTableRowDesktop = (props: any) => { )} - {Object.entries(feat.tiers).map((entry: any, i) => { - const tierName = entry[0] - const tierValue = entry[1] + {Object.entries(feat.plans).map((entry: any, i) => { + const planName = entry[0] + const planValue = entry[1] return ( - {typeof tierValue === 'boolean' && tierValue === true ? ( - - ) : typeof tierValue === 'boolean' && tierValue === false ? ( + {typeof planValue === 'boolean' && planValue === true ? ( + + ) : typeof planValue === 'boolean' && planValue === false ? (
- +
) : ( - {feat.tooltips?.[tierName] && ( + {feat.tooltips?.[planName] && ( )} - {tierValue} + {planValue} )} @@ -96,7 +96,7 @@ export const PricingTableRowDesktop = (props: any) => { export const PricingTableRowMobile = (props: any) => { const category = props.category - const tier = props.tier + const plan = props.plan return ( <> @@ -127,16 +127,16 @@ export const PricingTableRowMobile = (props: any) => { - {typeof feat.tiers[tier] === 'boolean' && feat.tiers[tier] === true ? ( + {typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === true ? (
- +
- ) : typeof feat.tiers[tier] === 'boolean' && feat.tiers[tier] === false ? ( + ) : typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === false ? (
- +
) : ( - {feat.tiers[tier]} + {feat.plans[plan]} )} diff --git a/apps/www/data/products/realtime/app-examples.js b/apps/www/data/products/realtime/app-examples.js index 0979fabca71..5a7d7281c0c 100644 --- a/apps/www/data/products/realtime/app-examples.js +++ b/apps/www/data/products/realtime/app-examples.js @@ -41,7 +41,7 @@ export default [ img: 'whiteboard.svg', title: 'Shared whiteboard', description: - 'Allow users to collaorate on a shared whiteboard, sharing positions and states of any kind of object in Realtime.', + 'Allow users to collaborate on a shared whiteboard, sharing positions and states of any kind of object in Realtime.', }, { img: 'location.svg', diff --git a/apps/www/lib/mdx/mdxComponents.tsx b/apps/www/lib/mdx/mdxComponents.tsx index 5652a9e13b3..0ff6f996a7d 100644 --- a/apps/www/lib/mdx/mdxComponents.tsx +++ b/apps/www/lib/mdx/mdxComponents.tsx @@ -1,6 +1,7 @@ import Image from 'next/image' import Avatar from '~/components/Avatar' import CodeBlock from '~/components/CodeBlock/CodeBlock' +import { CH } from '@code-hike/mdx/components' import ImageGrid from '~/components/ImageGrid' import Quote from '~/components/Quote' import Chart from '~/components/Charts/PGCharts' @@ -28,6 +29,7 @@ const getCaptionAlign = (align?: 'left' | 'center' | 'right') => { export default function mdxComponents(type?: 'blog' | 'lp' | undefined) { const components = { CodeBlock, + CH, Badge, Quote, Avatar, diff --git a/apps/www/lib/mdx/mdxSerialize.ts b/apps/www/lib/mdx/mdxSerialize.ts index f5ed0ce9c9b..c959b7223a7 100644 --- a/apps/www/lib/mdx/mdxSerialize.ts +++ b/apps/www/lib/mdx/mdxSerialize.ts @@ -2,10 +2,24 @@ import { serialize } from 'next-mdx-remote/serialize' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' +import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } + export async function mdxSerialize(source: string) { + const codeHikeOptions: CodeHikeConfig = { + theme: codeHikeTheme, + lineNumbers: true, + showCopyButton: true, + skipLanguages: [], + autoImport: false, + } + const mdxSource: any = await serialize(source, { + scope: { + chCodeConfig: codeHikeOptions, + }, mdxOptions: { - remarkPlugins: [remarkGfm], + remarkPlugins: [[remarkCodeHike, codeHikeOptions], remarkGfm], rehypePlugins: [ // @ts-ignore rehypeSlug, // add IDs to any h1-h6 tag that doesn't have one, using a slug made from its text diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js index 8302c7e8aba..c96448e4c4b 100644 --- a/apps/www/lib/redirects.js +++ b/apps/www/lib/redirects.js @@ -1030,6 +1030,11 @@ module.exports = [ source: '/blog/2022/02/22/supabase-beta-january-2022', destination: '/blog/supabase-beta-january-2022', }, + { + permanent: true, + source: '/blog/audit', + destination: '/blog/postgres-audit', + }, { permanent: true, source: '/blog/2022/03/08/audit', @@ -1792,6 +1797,26 @@ module.exports = [ source: '/docs/reference/dart', destination: '/docs/reference/dart/start', }, + { + permanent: true, + source: '/docs/reference/python', + destination: '/docs/reference/python/start', + }, + { + permanent: true, + source: '/docs/reference/csharp', + destination: '/docs/reference/csharp/start', + }, + { + permanent: true, + source: '/docs/reference/swift', + destination: '/docs/reference/swift/start', + }, + { + permanent: true, + source: '/docs/reference/kotlin', + destination: '/docs/reference/kotlin/start', + }, { permanent: true, source: '/docs/reference/cli', diff --git a/apps/www/next.config.mjs b/apps/www/next.config.mjs index 599600fb9cd..cbd15868625 100644 --- a/apps/www/next.config.mjs +++ b/apps/www/next.config.mjs @@ -9,10 +9,23 @@ import redirects from './lib/redirects.js' import withTM from 'next-transpile-modules' +import { remarkCodeHike } from '@code-hike/mdx' +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } + const withMDX = nextMdx({ extension: /\.mdx?$/, options: { - remarkPlugins: [remarkGfm], + remarkPlugins: [ + [ + remarkCodeHike, + { + theme: codeHikeTheme, + lineNumbers: true, + showCopyButton: true, + }, + ], + remarkGfm, + ], rehypePlugins: [rehypeSlug], // This is required for `MDXProvider` component providerImportSource: '@mdx-js/react', @@ -77,6 +90,6 @@ const nextConfig = { // next.config.js. export default () => { - const plugins = [withMDX, withBundleAnalyzer, withTM(['ui', 'common'])] + const plugins = [withMDX, withBundleAnalyzer, withTM(['ui', 'common', 'shared-data'])] return plugins.reduce((acc, next) => next(acc), nextConfig) } diff --git a/apps/www/package.json b/apps/www/package.json index 06f9b0a3b00..70f04daba7a 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -13,6 +13,7 @@ "postbuild": "node ./internals/generate-sitemap.mjs" }, "dependencies": { + "@code-hike/mdx": "^0.8.3", "@heroicons/react": "^1.0.6", "@mdx-js/loader": "^2.1.5", "@mdx-js/react": "^2.1.5", @@ -54,6 +55,7 @@ "remark": "^14.0.2", "remark-gfm": "^3.0.1", "remark-html": "^15.0.1", + "shared-data": "*", "swiper": "^6.5.0", "swr": "^0.5.4", "typescript": "^5.0.4", diff --git a/apps/www/pages/_app.tsx b/apps/www/pages/_app.tsx index a101101cbc0..4ca575bd201 100644 --- a/apps/www/pages/_app.tsx +++ b/apps/www/pages/_app.tsx @@ -13,6 +13,7 @@ import '../styles/index.css' import { post } from '~/lib/fetchWrapper' import { AuthProvider, ThemeProvider, useTelemetryProps } from 'common' import Head from 'next/head' +import 'config/code-hike.scss' export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter() diff --git a/apps/www/pages/pricing/CHANGELOG.txt b/apps/www/pages/pricing/CHANGELOG.txt deleted file mode 100644 index 62db4f4b1ec..00000000000 --- a/apps/www/pages/pricing/CHANGELOG.txt +++ /dev/null @@ -1,99 +0,0 @@ -Pricing Changelog - -### 18 Jan 2023 - -- Clarified over-usage of Realtime messages per month - - On the Pro plan, $2.50 per million after included 5 million messages - -### 09 Jan 2023 ----- - -Database Compute Add ons -- Clarified iops values to the latest instance types - -### 02 Nov 2022 ----- - -Database -- guidance on backups > 1TB in size -- Removed "Realtime functionality" as it is redundant with new realtime section -Auth -- added “advanced security features” -- MAUs changed to unlimited for Enterprise -Realtime -— Added new realtime section -- Concurrent Peak Connections -- Max Messages Per Month -- Max Message Size -Edge Functions -- Runtime hours removed -- Number of functions, usage pricing added after limit on Pro -- Invocations, usage pricing added after limit on Pro -Support -- Security features moved to own section -Platform Security and Compliance -- New section made -- added Access roles -- added Custom Domains -- added Vanity URLs added -Database Compute Add ons -- New label “Optimized Compute” - - -### 16 June 2022 ----- - -Auth -- New item “MAUs (Monthly Active Users)” -Security & Compliance -- New item: “Security questionnaire help” for enterprise -- New item - “Metrics Endpoint” for enterprise and pro plan users -Database Compute Add ons -- New item: “4XL” -- New item: “8XL” -- New item: “12XL” -- New item: “16XL” -Database -- New item: “Point in time recovery” for enterprise -Clarifications -- General - Clearer language that we charge on a per project per month -- Storage - Uploads for Pro, changed from 3GB → 5GB in title card -- Storage - file upload size - clarified that it can be changed in dashboard -- All products - “Transfer” renamed to “Egress” -- Database compute add-ons - Number of connections more accurate -- Storage - Free plan egress per month clarified - -### 31 March 2022 ----- - -Edge Functions pricing announced - - -### 29 March 2022 ----- - -— Enterprise pricing plan announced - -— Pay as you go plan now the same as the Pro plan - - -27 August 2021 ----- - -- Changes "Dedicated support" to "Designated support". - - Dedicated = one individual solely focused on an account. - - Designated = individual who may be helping across various accounts, but still a single point of contact. May be dedicated or non-dedicated. - - -28 July 2021 ----- - -- Clarified pricing on the "Optimized database instances" to include the starting price of $50/month. - - -### 29 March 2021 ----- - -Released our Beta pricing. - - diff --git a/apps/www/pages/pricing/index.tsx b/apps/www/pages/pricing/index.tsx index 0f0f2e3cbc2..5d6089d50e5 100644 --- a/apps/www/pages/pricing/index.tsx +++ b/apps/www/pages/pricing/index.tsx @@ -8,21 +8,25 @@ import ReactMarkdown from 'react-markdown' import CTABanner from '~/components/CTABanner' import DefaultLayout from '~/components/Layouts/Default' import { PricingTableRowDesktop, PricingTableRowMobile } from '~/components/Pricing/PricingTableRow' -import pricing from '~/data/Pricing.json' +import pricing from 'shared-data/Pricing.json' import pricingFaq from '~/data/PricingFAQ.json' import { useTheme } from 'common/Providers' import ComputePricingModal from '~/components/Pricing/ComputePricingModal' +import { plans } from 'shared-data/plans' export default function IndexPage() { const router = useRouter() const { basePath, asPath } = useRouter() const { isDarkMode } = useTheme() const [showComputeModal, setShowComputeModal] = useState(false) - const [activeMobileTier, setActiveMobileTier] = useState('Free') + const [activeMobilePlan, setActiveMobilePlan] = useState('Free') const meta_title = 'Pricing & fees | Supabase' const meta_description = - 'Explore Supabase fees and pricing information. Find our competitive pricing tiers, with no hidden pricing. We have a generous free plan for those getting started, and Pay As You Go for those scaling up.' + 'Explore Supabase fees and pricing information. Find our competitive pricing plans, with no hidden pricing. We have a generous free plan for those getting started, and Pay As You Go for those scaling up.' + + const plansExceptEnterprise = plans.filter((it) => it.name !== 'Enterprise') + const planEnterprise = plans.find((it) => it.name === 'Enterprise')! // Ability to scroll into pricing sections like storage useEffect(() => { @@ -45,93 +49,6 @@ export default function IndexPage() { } }, [asPath]) - /** - * @mildtomato same plan metadata is also in /studio dashboard - * would be good if this constant was shared across apps - * - * https://github.com/supabase/supabase/blob/master/www/pages/pricing/index.tsx - */ - const tiers = [ - { - name: 'Free', - nameBadge: '', - costUnit: 'per month per project', - href: 'https://supabase.com/dashboard/new/new-project', - priceLabel: 'Starting from', - priceMonthly: 0, - warning: 'Limit of 2 free projects', - description: 'Perfect for passion projects & simple websites.', - preface: 'Get started with:', - features: [ - 'Social OAuth providers', - 'Up to 500MB database & 1GB file storage', - 'Up to 2GB bandwidth', - 'Up to 50MB file uploads', - '50,000 monthly active users', - 'Up to 500K Edge Function invocations', - '200 concurrent Realtime connections', - '2 million Realtime messages', - '1-day log retention', - 'Community support', - ], - scale: 'Free projects are paused after 1 week of inactivity.', - - cta: 'Get Started', - }, - { - name: 'Pro', - nameBadge: '', - costUnit: 'per month per project', - href: 'https://supabase.com/dashboard/new/new-project', - from: true, - priceLabel: 'Starting from', - warning: '+ usage', - priceMonthly: 25, - description: 'For production applications with the option to scale.', - features: [ - 'No project pausing', - '8GB database & 100GB file storage', - '50GB bandwidth', - '5GB file uploads', - '100,000 monthly active users', - '2M Edge Function invocations', - '500 concurrent Realtime connections', - '5 million Realtime messages', - '7-day log retention', - 'Email support', - 'Daily backups', - ], - scale: 'Additional fees apply for usage and storage beyond the limits above.', - shutdown: '', - preface: 'Everything in the Free plan, plus:', - additional: '', - cta: 'Get Started', - }, - { - name: 'Enterprise', - href: 'https://forms.supabase.com/enterprise', - description: 'For large-scale applications managing serious workloads.', - features: [ - `Designated Support manager & SLAs`, - `Enterprise OAuth providers`, - `SSO/ SAML`, - `SOC2`, - `Custom contracts & invoicing`, - `On-premise support`, - `24×7×365 premium enterprise support`, - `Custom Security questionnaires`, - `Private Slack channel`, - `Uptime SLA`, - ], - priceLabel: '', - priceMonthly: 'Contact us', - preface: 'These apply to all projects within the organization:', - scale: '', - shutdown: '', - cta: 'Contact Us', - }, - ] - const addons = [ { name: 'Optimized Compute', @@ -174,21 +91,21 @@ export default function IndexPage() { description, priceDescription, price, - tier, + plan, showDollarSign = true, from = false, }: { description: string priceDescription: string price: string - tier: string + plan: string showDollarSign?: boolean from?: boolean }) => { return (

- {tier} + {plan}

{from && From} @@ -242,7 +159,7 @@ export default function IndexPage() {
-
+
{/*
*/}
- {tiers.map((tier) => ( + {plansExceptEnterprise.map((plan) => (
- {tier.name === 'Pro' && ( + {plan.name === 'Pro' && (

Most Popular

)}
@@ -282,55 +199,56 @@ export default function IndexPage() { className="gradient-text-brand-500 dark:gradient-text-brand-100 text-2xl font-normal uppercase flex items-center gap-4 font-mono" > - {tier.name} + {plan.name} - {tier.nameBadge && ( - - {tier.nameBadge} + {plan.nameBadge && ( + + {plan.nameBadge} )}
-

- {tier.description} +

+ {plan.description}

-

- {tier.priceLabel} -

-

- {tier.name !== 'Enterprise' && '$'} - {tier.priceMonthly} -

- {tier.costUnit && ( -

{tier.costUnit}

+ {plan.priceLabel && ( +

+ {plan.priceLabel} +

)} - {tier.warning && ( +
+

+ ${plan.priceMonthly} +

+

+ {plan.costUnit} +

+
+ + {plan.warning && (

- - {tier.warning} + + {plan.warning}

)} @@ -342,18 +260,18 @@ export default function IndexPage() {
- {tier.preface && ( -

{tier.preface}

+ {plan.preface && ( +

{plan.preface}

)} {/*

Included with plan:

*/}
    - {tier.features.map((feature) => ( + {plan.features.map((feature) => (
+ +
+
+
+
+

+ {planEnterprise.name} +

+

+ {planEnterprise.description} +

+ + + + +
+
+
+
    + {planEnterprise.features.map((feature) => ( +
  • +
  • + ))} +
+ + + + +
+
+
+
-
- -
+
@@ -519,79 +478,80 @@ export default function IndexPage() { id="change-plan" name="Change plan" layout="vertical" - value={activeMobileTier} + value={activeMobilePlan} className="min-w-[120px] bg-slate-400 text-red-500" - onChange={(e) => setActiveMobileTier(e.target.value)} + onChange={(e) => setActiveMobilePlan(e.target.value)} > Free Pro + Team Enterprise
- {activeMobileTier === 'Free' && ( + {activeMobilePlan === 'Free' && ( <> )} - {activeMobileTier === 'Pro' && ( + {activeMobilePlan === 'Pro' && ( <> )} - {activeMobileTier === 'Enterprise' && ( + {activeMobilePlan === 'Team' && ( <> + + + + + + + + + + )} + + {activeMobilePlan === 'Enterprise' && ( + <> + @@ -712,14 +724,14 @@ export default function IndexPage() { >
- {tiers.map((tier) => ( + {plans.map((plan) => (

- {tier.name} + {plan.name}

- {tiers.map((tier) => ( + {plans.map((plan) => ( -

{tier.description}

+

{plan.description}

- + - {tiers.map((tier) => ( - + {plans.map((plan) => ( +
<> - {tier.name !== 'Enterprise' && '$'} - {tier.priceMonthly} + {plan.name !== 'Enterprise' && '$'} + {plan.priceMonthly} - {tier.name !== 'Enterprise' && ( -

per project per month

+ {['Pro', 'Free'].includes(plan.name) && ( +

per month

+ )} + {['Team'].includes(plan.name) && ( +

per month

)} - {tier.warning && ( + {plan.warning && (

- - {tier.warning} + + {plan.warning}

)} -
- +
+ @@ -875,7 +890,7 @@ export default function IndexPage() { - + + + + diff --git a/apps/www/public/images/blog/avatars/ishaan-jaffer.png b/apps/www/public/images/blog/avatars/ishaan-jaffer.png new file mode 100644 index 00000000000..707ca00bc16 Binary files /dev/null and b/apps/www/public/images/blog/avatars/ishaan-jaffer.png differ diff --git a/apps/www/public/images/blog/avatars/krrish-d.png b/apps/www/public/images/blog/avatars/krrish-d.png new file mode 100644 index 00000000000..baf79787368 Binary files /dev/null and b/apps/www/public/images/blog/avatars/krrish-d.png differ diff --git a/apps/www/public/images/customers/logos/berriai.png b/apps/www/public/images/customers/logos/berriai.png new file mode 100644 index 00000000000..b5dddd2df31 Binary files /dev/null and b/apps/www/public/images/customers/logos/berriai.png differ diff --git a/apps/www/public/images/customers/logos/light/berriai.png b/apps/www/public/images/customers/logos/light/berriai.png new file mode 100644 index 00000000000..abdca8e700a Binary files /dev/null and b/apps/www/public/images/customers/logos/light/berriai.png differ diff --git a/apps/www/public/images/customers/og/berriai.jpg b/apps/www/public/images/customers/og/berriai.jpg new file mode 100644 index 00000000000..4c03379e4cd Binary files /dev/null and b/apps/www/public/images/customers/og/berriai.jpg differ diff --git a/apps/www/styles/index.css b/apps/www/styles/index.css index 50fd685751c..27d9b17a541 100644 --- a/apps/www/styles/index.css +++ b/apps/www/styles/index.css @@ -148,7 +148,7 @@ h6:not(.overwrite) { } ::selection { - background-color: #6ee7b7; + background-color: #6ee7b7 !important; color: #333 !important; } diff --git a/examples/todo-list/sveltejs-todo-list/package-lock.json b/examples/todo-list/sveltejs-todo-list/package-lock.json index 8130f4a0c4e..d15d479af9c 100644 --- a/examples/todo-list/sveltejs-todo-list/package-lock.json +++ b/examples/todo-list/sveltejs-todo-list/package-lock.json @@ -21,13 +21,29 @@ "tailwindcss": "^3.1.8", "tslib": "^2.4.0", "typescript": "^4.7.4", - "vite": "^3.0.0" + "vite": "^3.2.7" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz", - "integrity": "sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "cpu": [ "loong64" ], @@ -660,9 +676,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.53.tgz", - "integrity": "sha512-ohO33pUBQ64q6mmheX1mZ8mIXj8ivQY/L4oVuAshr+aJI+zLl+amrp3EodrUNDNYVrKJXGPfIHFGhO8slGRjuw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, "hasInstallScript": true, "bin": { @@ -672,33 +688,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/linux-loong64": "0.14.53", - "esbuild-android-64": "0.14.53", - "esbuild-android-arm64": "0.14.53", - "esbuild-darwin-64": "0.14.53", - "esbuild-darwin-arm64": "0.14.53", - "esbuild-freebsd-64": "0.14.53", - "esbuild-freebsd-arm64": "0.14.53", - "esbuild-linux-32": "0.14.53", - "esbuild-linux-64": "0.14.53", - "esbuild-linux-arm": "0.14.53", - "esbuild-linux-arm64": "0.14.53", - "esbuild-linux-mips64le": "0.14.53", - "esbuild-linux-ppc64le": "0.14.53", - "esbuild-linux-riscv64": "0.14.53", - "esbuild-linux-s390x": "0.14.53", - "esbuild-netbsd-64": "0.14.53", - "esbuild-openbsd-64": "0.14.53", - "esbuild-sunos-64": "0.14.53", - "esbuild-windows-32": "0.14.53", - "esbuild-windows-64": "0.14.53", - "esbuild-windows-arm64": "0.14.53" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "node_modules/esbuild-android-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz", - "integrity": "sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "cpu": [ "x64" ], @@ -712,9 +729,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz", - "integrity": "sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "cpu": [ "arm64" ], @@ -728,9 +745,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz", - "integrity": "sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "cpu": [ "x64" ], @@ -744,9 +761,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz", - "integrity": "sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "cpu": [ "arm64" ], @@ -760,9 +777,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz", - "integrity": "sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "cpu": [ "x64" ], @@ -776,9 +793,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz", - "integrity": "sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "cpu": [ "arm64" ], @@ -792,9 +809,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz", - "integrity": "sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "cpu": [ "ia32" ], @@ -808,9 +825,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz", - "integrity": "sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "cpu": [ "x64" ], @@ -824,9 +841,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz", - "integrity": "sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "cpu": [ "arm" ], @@ -840,9 +857,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz", - "integrity": "sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "cpu": [ "arm64" ], @@ -856,9 +873,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz", - "integrity": "sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "cpu": [ "mips64el" ], @@ -872,9 +889,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz", - "integrity": "sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "cpu": [ "ppc64" ], @@ -888,9 +905,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz", - "integrity": "sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "cpu": [ "riscv64" ], @@ -904,9 +921,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz", - "integrity": "sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "cpu": [ "s390x" ], @@ -920,9 +937,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz", - "integrity": "sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "cpu": [ "x64" ], @@ -936,9 +953,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz", - "integrity": "sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "cpu": [ "x64" ], @@ -952,9 +969,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz", - "integrity": "sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "cpu": [ "x64" ], @@ -968,9 +985,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz", - "integrity": "sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "cpu": [ "ia32" ], @@ -984,9 +1001,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz", - "integrity": "sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "cpu": [ "x64" ], @@ -1000,9 +1017,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz", - "integrity": "sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "cpu": [ "arm64" ], @@ -1399,10 +1416,16 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1526,9 +1549,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "dev": true, "funding": [ { @@ -1538,10 +1561,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -1763,9 +1790,9 @@ } }, "node_modules/rollup": { - "version": "2.77.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", - "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -2181,15 +2208,15 @@ "dev": true }, "node_modules/vite": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.0.4.tgz", - "integrity": "sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "dependencies": { - "esbuild": "^0.14.47", - "postcss": "^8.4.14", + "esbuild": "^0.15.9", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "^2.75.6" + "rollup": "^2.79.1" }, "bin": { "vite": "bin/vite.js" @@ -2201,12 +2228,17 @@ "fsevents": "~2.3.2" }, "peerDependencies": { + "@types/node": ">= 14", "less": "*", "sass": "*", "stylus": "*", + "sugarss": "*", "terser": "^5.4.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "less": { "optional": true }, @@ -2216,6 +2248,9 @@ "stylus": { "optional": true }, + "sugarss": { + "optional": true + }, "terser": { "optional": true } @@ -2351,10 +2386,17 @@ } }, "dependencies": { + "@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "dev": true, + "optional": true + }, "@esbuild/linux-loong64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz", - "integrity": "sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "dev": true, "optional": true }, @@ -2845,171 +2887,172 @@ } }, "esbuild": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.53.tgz", - "integrity": "sha512-ohO33pUBQ64q6mmheX1mZ8mIXj8ivQY/L4oVuAshr+aJI+zLl+amrp3EodrUNDNYVrKJXGPfIHFGhO8slGRjuw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, "requires": { - "@esbuild/linux-loong64": "0.14.53", - "esbuild-android-64": "0.14.53", - "esbuild-android-arm64": "0.14.53", - "esbuild-darwin-64": "0.14.53", - "esbuild-darwin-arm64": "0.14.53", - "esbuild-freebsd-64": "0.14.53", - "esbuild-freebsd-arm64": "0.14.53", - "esbuild-linux-32": "0.14.53", - "esbuild-linux-64": "0.14.53", - "esbuild-linux-arm": "0.14.53", - "esbuild-linux-arm64": "0.14.53", - "esbuild-linux-mips64le": "0.14.53", - "esbuild-linux-ppc64le": "0.14.53", - "esbuild-linux-riscv64": "0.14.53", - "esbuild-linux-s390x": "0.14.53", - "esbuild-netbsd-64": "0.14.53", - "esbuild-openbsd-64": "0.14.53", - "esbuild-sunos-64": "0.14.53", - "esbuild-windows-32": "0.14.53", - "esbuild-windows-64": "0.14.53", - "esbuild-windows-arm64": "0.14.53" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "esbuild-android-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz", - "integrity": "sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "dev": true, "optional": true }, "esbuild-android-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz", - "integrity": "sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz", - "integrity": "sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz", - "integrity": "sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz", - "integrity": "sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz", - "integrity": "sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz", - "integrity": "sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz", - "integrity": "sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz", - "integrity": "sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz", - "integrity": "sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz", - "integrity": "sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz", - "integrity": "sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "dev": true, "optional": true }, "esbuild-linux-riscv64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz", - "integrity": "sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "dev": true, "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz", - "integrity": "sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz", - "integrity": "sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz", - "integrity": "sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz", - "integrity": "sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "dev": true, "optional": true }, "esbuild-windows-32": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz", - "integrity": "sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz", - "integrity": "sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.53", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz", - "integrity": "sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "dev": true, "optional": true }, @@ -3313,9 +3356,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true }, "next-tick": { @@ -3397,12 +3440,12 @@ "dev": true }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -3531,9 +3574,9 @@ } }, "rollup": { - "version": "2.77.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", - "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -3808,16 +3851,16 @@ "dev": true }, "vite": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.0.4.tgz", - "integrity": "sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "requires": { - "esbuild": "^0.14.47", + "esbuild": "^0.15.9", "fsevents": "~2.3.2", - "postcss": "^8.4.14", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "^2.75.6" + "rollup": "^2.79.1" } }, "webidl-conversions": { diff --git a/examples/todo-list/sveltejs-todo-list/package.json b/examples/todo-list/sveltejs-todo-list/package.json index bd62d122e37..28908c55c0d 100644 --- a/examples/todo-list/sveltejs-todo-list/package.json +++ b/examples/todo-list/sveltejs-todo-list/package.json @@ -22,7 +22,7 @@ "tailwindcss": "^3.1.8", "tslib": "^2.4.0", "typescript": "^4.7.4", - "vite": "^3.0.0" + "vite": "^3.2.7" }, "dependencies": { "@supabase/supabase-js": "^2.0.4" diff --git a/examples/user-management/sveltekit-user-management/package-lock.json b/examples/user-management/sveltekit-user-management/package-lock.json index 1f46a55694e..5277f482c43 100644 --- a/examples/user-management/sveltekit-user-management/package-lock.json +++ b/examples/user-management/sveltekit-user-management/package-lock.json @@ -26,7 +26,7 @@ "svelte-preprocess": "^5.0.3", "tslib": "^2.5.0", "typescript": "^5.0.4", - "vite": "^4.3.5" + "vite": "^4.3.9" } }, "node_modules/@esbuild/android-arm": { @@ -1782,9 +1782,9 @@ } }, "node_modules/vite": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.5.tgz", - "integrity": "sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dependencies": { "esbuild": "^0.17.5", "postcss": "^8.4.23", diff --git a/examples/user-management/sveltekit-user-management/package.json b/examples/user-management/sveltekit-user-management/package.json index 66ae7e452b9..70f85ae4f02 100644 --- a/examples/user-management/sveltekit-user-management/package.json +++ b/examples/user-management/sveltekit-user-management/package.json @@ -23,7 +23,7 @@ "svelte-preprocess": "^5.0.3", "tslib": "^2.5.0", "typescript": "^5.0.4", - "vite": "^4.3.5" + "vite": "^4.3.9" }, "type": "module", "dependencies": { diff --git a/examples/user-management/vue3-user-management/package-lock.json b/examples/user-management/vue3-user-management/package-lock.json index af762cc7613..00fbcc38620 100644 --- a/examples/user-management/vue3-user-management/package-lock.json +++ b/examples/user-management/vue3-user-management/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.0", - "vite": "^3.1.0" + "vite": "^3.2.7" } }, "node_modules/@babel/parser": { @@ -842,9 +842,9 @@ } }, "node_modules/rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -920,15 +920,15 @@ } }, "node_modules/vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "dependencies": { "esbuild": "^0.15.9", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" + "rollup": "^2.79.1" }, "bin": { "vite": "bin/vite.js" @@ -940,12 +940,17 @@ "fsevents": "~2.3.2" }, "peerDependencies": { + "@types/node": ">= 14", "less": "*", "sass": "*", "stylus": "*", + "sugarss": "*", "terser": "^5.4.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "less": { "optional": true }, @@ -955,6 +960,9 @@ "stylus": { "optional": true }, + "sugarss": { + "optional": true + }, "terser": { "optional": true } @@ -1558,9 +1566,9 @@ } }, "rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -1614,16 +1622,16 @@ } }, "vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", + "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", "dev": true, "requires": { "esbuild": "^0.15.9", "fsevents": "~2.3.2", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" + "rollup": "^2.79.1" } }, "vue": { diff --git a/examples/user-management/vue3-user-management/package.json b/examples/user-management/vue3-user-management/package.json index 07d2627d076..5717df6a9ce 100644 --- a/examples/user-management/vue3-user-management/package.json +++ b/examples/user-management/vue3-user-management/package.json @@ -14,6 +14,6 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.0", - "vite": "^3.1.0" + "vite": "^3.2.7" } } diff --git a/i18n/README.ar.md b/i18n/README.ar.md index eb708f5d4b5..c527ed5d2c1 100644 --- a/i18n/README.ar.md +++ b/i18n/README.ar.md @@ -35,7 +35,7 @@ ## الحالة - [x] طور الألفا: نحن نختبر Supabase مع مجموعة مغلقة من العملاء -- [x] طور الألفا العام: يمكن لأي شخص الاشتراك في [app.supabase.com] (https://app.supabase.com). لكن تحلى بالصبر ، فهناك بعض العقد الصغيرة. +- [x] طور الألفا العام: يمكن لأي شخص الاشتراك في [app.supabase.com](https://app.supabase.com). لكن تحلى بالصبر ، فهناك بعض العقد الصغيرة. - [x] طور البيتا العام: مستقر بدرجة كافية لمعظم حالات الاستخدام غير المتعلقة بالمؤسسات - [ ] الطور العام: جاهز للإنتاج diff --git a/i18n/README.da.md b/i18n/README.da.md index 34c6a5ff495..96d1bb41c49 100644 --- a/i18n/README.da.md +++ b/i18n/README.da.md @@ -7,7 +7,7 @@ # Supabase -[Supabase] (https://supabase.com) er et Open Source Firebase-alternativ. Vi opbygger Firebase-funktionerne ved hjælp af open source-værktøjer i virksomhedskvalitet. +[Supabase](https://supabase.com) er et Open Source Firebase-alternativ. Vi opbygger Firebase-funktionerne ved hjælp af open source-værktøjer i virksomhedskvalitet. - [x] Hosted Postgres Database. [Docs](https://supabase.com/docs/guides/database) - [x] Autentifikation og autorisering. [Docs](https://supabase.com/docs/guides/auth) @@ -39,7 +39,7 @@ For at se, hvordan man bidrager, besøg [Getting Started](./DEVELOPERS.md) ## Status - [x] Alpha: Vi tester Supabase med et lukket sæt af kunder -- [x] Offentlig Alpha: Alle kan tilmelde sig på [app.supabase.com] (https://app.supabase.com). Men vær forsigtig med os, der er et par knuder +- [x] Offentlig Alpha: Alle kan tilmelde sig på [app.supabase.com](https://app.supabase.com). Men vær forsigtig med os, der er et par knuder - [x] Public Beta: Stabil nok til de fleste ikke-virksomhedsrelaterede brugssager - [ ] Public: Public: Generel tilgængelighed [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)] @@ -55,14 +55,14 @@ Supabase er en kombination af open source-værktøjer. Vi opbygger funktionerne **Arkitektur** -Supabase er en [hosted platform] (https://app.supabase.com). Du kan tilmelde dig og begynde at bruge Supabase uden at installere noget. +Supabase er en [hosted platform](https://app.supabase.com). Du kan tilmelde dig og begynde at bruge Supabase uden at installere noget. Du kan også [selv hoste](https://supabase.com/docs/guides/hosting/overview) og [udvikle lokalt](https://supabase.com/docs/guides/local-development). ![Arkitektur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/) er et objektrelationelt databasesystem med over 30 års aktiv udvikling, der har givet det et godt ry for pålidelighed, robusthed og ydeevne. - [Realtime](https://github.com/supabase/realtime) er en Elixir-server, der giver dig mulighed for at lytte til PostgreSQL-indsættelser, -opdateringer og -slettelser ved hjælp af websockets. Realtime spørger Postgres' indbyggede replikationsfunktionalitet efter databaseændringer, konverterer ændringer til JSON og sender derefter JSON'en over websockets til autoriserede klienter. -- [PostgREST] (http://postgrest.org/) er en webserver, der forvandler din PostgreSQL-database direkte til et RESTful API +- [PostgREST](http://postgrest.org/) er en webserver, der forvandler din PostgreSQL-database direkte til et RESTful API - [pg_graphql](http://github.com/supabase/pg_graphql/) er en PostgreSQL-udvidelse, der eksponerer et GraphQL API - [Storage](https://github.com/supabase/storage-api) giver en RESTful grænseflade til administration af filer gemt i S3, der bruger Postgres til at administrere tilladelser. - [postgres-meta](https://github.com/supabase/postgres-meta) er et RESTful API til administration af din Postgres, så du kan hente tabeller, tilføje roller og køre forespørgsler osv. diff --git a/i18n/README.de.md b/i18n/README.de.md index 7160931117d..59b45286a59 100644 --- a/i18n/README.de.md +++ b/i18n/README.de.md @@ -55,8 +55,8 @@ Supabase ist eine Kombination aus Open-Source-Tools. Wir entwickeln die Funktion **Architektur** -Supabase ist eine [gehostete Plattform] (https://app.supabase.com). Sie können sich anmelden und Supabase verwenden, ohne etwas zu installieren. -Sie können auch [selbst hosten] (https://supabase.com/docs/guides/hosting/overview) und [lokal entwickeln] (https://supabase.com/docs/guides/local-development). +Supabase ist eine [gehostete Plattform](https://app.supabase.com). Sie können sich anmelden und Supabase verwenden, ohne etwas zu installieren. +Sie können auch [selbst hosten](https://supabase.com/docs/guides/hosting/overview) und [lokal entwickeln](https://supabase.com/docs/guides/local-development). ![Architektur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.es.md b/i18n/README.es.md index 7a7b9c0b666..226e67fadce 100644 --- a/i18n/README.es.md +++ b/i18n/README.es.md @@ -53,7 +53,7 @@ Actualmente estamos en Beta Pública. Esté atento a "releases" de este reposito Supabase es una combinación de herramientas de código abierto. Estamos construyendo las características de Firebase utilizando productos de código abierto de nivel empresarial. Si las herramientas y las comunidades existen, con una licencia abierta MIT, Apache 2 o equivalente, utilizaremos y daremos soporte a esa herramienta. Si la herramienta no existe, la construimos y la desarrollamos nosotros mismos. Supabase no es un mapeo 1 a 1 de Firebase. Nuestro objetivo es ofrecer a los desarrolladores una experiencia similar a la de Firebase utilizando herramientas de código abierto. -\*\*Arquitectura +**Arquitectura** Supabase es una [plataforma alojada](https://app.supabase.com). Puedes registrarte y empezar a usar Supabase sin instalar nada. También puede [autoalojarse](https://supabase.com/docs/guides/hosting/overview) y [desarrollar localmente](https://supabase.com/docs/guides/local-development). diff --git a/i18n/README.fr.md b/i18n/README.fr.md index 2d3356c4f72..97f95c2a9c8 100644 --- a/i18n/README.fr.md +++ b/i18n/README.fr.md @@ -39,7 +39,7 @@ Pour savoir comment contribuer, visitez [Getting Started](./DEVELOPERS.md) ## Statut - [x] Alpha : Nous testons Supabase avec un groupe fermé de clients -- [x] Alpha publique : Tout le monde peut s'inscrire sur [app.supabase.com] (https://app.supabase.com). Mais allez-y doucement, il y a quelques problèmes +- [x] Alpha publique : Tout le monde peut s'inscrire sur [app.supabase.com](https://app.supabase.com). Mais allez-y doucement, il y a quelques problèmes - [x] Bêta publique : Suffisamment stable pour la plupart des cas d'utilisation hors entreprise - [ ] Public : Disponibilité générale [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)] @@ -55,14 +55,14 @@ Supabase est une combinaison d'outils open source. Nous construisons les fonctio **Architecture** -Supabase est une [plateforme hébergée] (https://app.supabase.com). Vous pouvez vous inscrire et commencer à utiliser Supabase sans rien installer. +Supabase est une [plateforme hébergée](https://app.supabase.com). Vous pouvez vous inscrire et commencer à utiliser Supabase sans rien installer. Vous pouvez également [auto-héberger](https://supabase.com/docs/guides/hosting/overview) et [développer localement](https://supabase.com/docs/guides/local-development). ![Architecture](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/) est un système de base de données objet-relationnel avec plus de 30 ans de développement actif qui lui a valu une solide réputation de fiabilité, de robustesse et de performance. - [Realtime](https://github.com/supabase/realtime) est un serveur Elixir qui vous permet d'écouter les insertions, les mises à jour et les suppressions de PostgreSQL en utilisant des websockets. Realtime interroge la fonctionnalité de réplication intégrée de Postgres pour les changements de base de données, convertit les changements en JSON, puis diffuse le JSON via des websockets aux clients autorisés. -- [PostgREST] (http://postgrest.org/) est un serveur web qui transforme votre base de données PostgreSQL en une API RESTful +- [PostgREST](http://postgrest.org/) est un serveur web qui transforme votre base de données PostgreSQL en une API RESTful - [pg_graphql](http://github.com/supabase/pg_graphql/) est une extension de PostgreSQL qui expose une API GraphQL - [Storage](https://github.com/supabase/storage-api) fournit une interface RESTful pour gérer les fichiers stockés dans S3, en utilisant Postgres pour gérer les permissions. - [postgres-meta](https://github.com/supabase/postgres-meta) est une API RESTful pour gérer votre Postgres, vous permettant de récupérer des tables, d'ajouter des rôles, et d'exécuter des requêtes, etc. diff --git a/i18n/README.id.md b/i18n/README.id.md index 984154f2d82..4a3e5036797 100644 --- a/i18n/README.id.md +++ b/i18n/README.id.md @@ -7,7 +7,7 @@ # Supabase -[Supabase] (https://supabase.com) adalah alternatif Firebase open source. Kami membangun fitur-fitur Firebase menggunakan alat bantu open source tingkat perusahaan. +[Supabase](https://supabase.com) adalah alternatif Firebase open source. Kami membangun fitur-fitur Firebase menggunakan alat bantu open source tingkat perusahaan. - [x] Basis Data Postgres yang dihosting. [Dokumen](https://supabase.com/docs/guides/database) - [x] Otentikasi dan Otorisasi. [Dokumen](https://supabase.com/docs/guides/auth) @@ -55,19 +55,19 @@ Supabase adalah kombinasi dari alat sumber terbuka. Kami membangun fitur-fitur F **Arsitektur** -Supabase adalah [platform yang di-host] (https://app.supabase.com). Anda bisa mendaftar dan mulai menggunakan Supabase tanpa menginstal apa pun. +Supabase adalah [platform yang di-host](https://app.supabase.com). Anda bisa mendaftar dan mulai menggunakan Supabase tanpa menginstal apa pun. Anda juga bisa [menghosting sendiri](https://supabase.com/docs/guides/hosting/overview) dan [mengembangkan secara lokal](https://supabase.com/docs/guides/local-development). ![Arsitektur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/) adalah sistem basis data relasional objek dengan lebih dari 30 tahun pengembangan aktif yang telah membuatnya memiliki reputasi yang kuat dalam hal keandalan, ketangguhan fitur, dan kinerja. -- [Realtime] (https://github.com/supabase/realtime) adalah server Elixir yang memungkinkan Anda untuk mendengarkan penyisipan, pembaruan, dan penghapusan PostgreSQL menggunakan websocket. Realtime melakukan polling terhadap fungsionalitas replikasi bawaan Postgres untuk perubahan database, mengkonversi perubahan ke JSON, kemudian menyiarkan JSON melalui websockets ke klien yang berwenang. -- [PostgREST] (http://postgrest.org/) adalah server web yang mengubah basis data PostgreSQL Anda secara langsung menjadi RESTful API -- [pg_graphql] (http://github.com/supabase/pg_graphql/) ekstensi PostgreSQL yang mengekspos API GraphQL +- [Realtime](https://github.com/supabase/realtime) adalah server Elixir yang memungkinkan Anda untuk mendengarkan penyisipan, pembaruan, dan penghapusan PostgreSQL menggunakan websocket. Realtime melakukan polling terhadap fungsionalitas replikasi bawaan Postgres untuk perubahan database, mengkonversi perubahan ke JSON, kemudian menyiarkan JSON melalui websockets ke klien yang berwenang. +- [PostgREST](http://postgrest.org/) adalah server web yang mengubah basis data PostgreSQL Anda secara langsung menjadi RESTful API +- [pg_graphql](http://github.com/supabase/pg_graphql/) ekstensi PostgreSQL yang mengekspos API GraphQL - [Storage](https://github.com/supabase/storage-api) menyediakan antarmuka RESTful untuk mengelola File yang disimpan di S3, menggunakan Postgres untuk mengelola izin. - [postgres-meta](https://github.com/supabase/postgres-meta) adalah API RESTful untuk mengelola Postgres Anda, yang memungkinkan Anda untuk mengambil tabel, menambahkan peran, dan menjalankan kueri, dll. -- [GoTrue] (https://github.com/netlify/gotrue) adalah API berbasis SWT untuk mengelola pengguna dan menerbitkan token SWT. -- [Kong] (https://github.com/Kong/kong) adalah gateway API asli cloud. +- [GoTrue](https://github.com/netlify/gotrue) adalah API berbasis SWT untuk mengelola pengguna dan menerbitkan token SWT. +- [Kong](https://github.com/Kong/kong) adalah gateway API asli cloud. #### Perpustakaan klien @@ -239,7 +239,7 @@ Pendekatan kami untuk pustaka klien bersifat modular. Setiap sub-pustaka adalah - [Bahasa Polandia / Polski](/i18n/README.pl.md) - [Bahasa Portugis / Português](/i18n/README.pt.md) - [Portugis (Brasil) / Português Brasileiro](/i18n/README.pt-br.md) -- [Bahasa Rumania / Rumania] (/i18n/README.ro.md) +- [Bahasa Rumania / Rumania](/i18n/README.ro.md) - [Bahasa Rusia / Pусский](/i18n/README.ru.md) - [Bahasa Serbia / Srpski](/i18n/README.sr.md) - [Sinhala / සිංහල](/i18n/README.si.md) diff --git a/i18n/README.it.md b/i18n/README.it.md index d35c45d9b19..0c0972fdeab 100644 --- a/i18n/README.it.md +++ b/i18n/README.it.md @@ -55,7 +55,7 @@ Supabase è una combinazione di strumenti open source. Stiamo costruendo le funz **Architettura** -Supabase è una [piattaforma ospitata] (https://app.supabase.com). È possibile registrarsi e iniziare a usare Supabase senza installare nulla. +Supabase è una [piattaforma ospitata](https://app.supabase.com). È possibile registrarsi e iniziare a usare Supabase senza installare nulla. È anche possibile [auto-ospitare](https://supabase.com/docs/guides/hosting/overview) e [sviluppare localmente](https://supabase.com/docs/guides/local-development). ![Architettura](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.lt.md b/i18n/README.lt.md index ecf7c71d5e3..194c0630c76 100644 --- a/i18n/README.lt.md +++ b/i18n/README.lt.md @@ -32,14 +32,14 @@ Norėdami sužinoti, kaip prisidėti, apsilankykite [Getting Started](./DEVELOPE ## Bendruomenė ir palaikymas - [Bendrijos forumas](https://github.com/supabase/supabase/discussions). Geriausiai tinka: pagalbai kuriant, diskusijoms apie geriausią duomenų bazių praktiką. -- [GitHub Issues] (https://github.com/supabase/supabase/issues). Geriausia: klaidos ir klaidos, su kuriomis susiduriate naudodami "Supabase". +- [GitHub Issues](https://github.com/supabase/supabase/issues). Geriausia: klaidos ir klaidos, su kuriomis susiduriate naudodami "Supabase". - [Pagalba el. paštu](https://supabase.com/docs/support#business-support). Geriausiai tinka: problemoms, susijusioms su jūsų duomenų baze ar infrastruktūra, spręsti. - [Discord](https://discord.supabase.com). Geriausiai tinka: dalytis savo programomis ir bendrauti su bendruomene. ## Statusas - [x] Alfa: Bandome "Supabase" su uždaru klientų rinkiniu -- [x] Viešoji Alfa versija: [app.supabase.com] (https://app.supabase.com). Tačiau neskubėkite su mumis, yra keletas trūkumų +- [x] Viešoji Alfa versija: [app.supabase.com](https://app.supabase.com). Tačiau neskubėkite su mumis, yra keletas trūkumų - [x] Viešoji beta versija: Pakankamai stabili daugeliui ne įmonių naudojimo atvejų - [ ] Vieša: Bendras prieinamumas [[statusas](https://supabase.com/docs/guides/getting-started/features#feature-status)] diff --git a/i18n/README.nb.md b/i18n/README.nb.md index 4fcd638925c..8e2ad57ea13 100644 --- a/i18n/README.nb.md +++ b/i18n/README.nb.md @@ -55,14 +55,14 @@ Supabase er en kombinasjon av verktøy med åpen kildekode. Vi bygger funksjonen \*\*Arkitektur -Supabase er en [vertsplattform] (https://app.supabase.com). Du kan registrere deg og begynne å bruke Supabase uten å installere noe. +Supabase er en [vertsplattform](https://app.supabase.com). Du kan registrere deg og begynne å bruke Supabase uten å installere noe. Du kan også [selv være vert](https://supabase.com/docs/guides/hosting/overview) og [utvikle lokalt](https://supabase.com/docs/guides/local-development). arkitektur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/) er et objektrelasjonsdatabasesystem med over 30 års aktiv utvikling som har gitt det et sterkt rykte for pålitelighet, robusthet og ytelse. - [Realtime](https://github.com/supabase/realtime) er en Elixir-server som lar deg lytte til PostgreSQL-innlegg, oppdateringer og slettinger ved hjelp av websockets. Realtime polls Postgres' innebygde replikeringsfunksjonalitet for databaseendringer, konverterer endringer til JSON og sender deretter JSON over websockets til autoriserte klienter. -- [PostgREST] (http://postgrest.org/) er en webserver som gjør PostgreSQL-databasen din direkte om til et RESTful API +- [PostgREST](http://postgrest.org/) er en webserver som gjør PostgreSQL-databasen din direkte om til et RESTful API - [pg_graphql](http://github.com/supabase/pg_graphql/) en PostgreSQL-utvidelse som eksponerer et GraphQL API - [Storage](https://github.com/supabase/storage-api) gir et RESTful-grensesnitt for å administrere filer som er lagret i S3, ved hjelp av Postgres for å administrere tillatelser. - [postgres-meta](https://github.com/supabase/postgres-meta) er et RESTful API for å administrere Postgres, slik at du kan hente tabeller, legge til roller og kjøre spørringer osv. diff --git a/i18n/README.nl.md b/i18n/README.nl.md index a155d5fc91b..ea486a4145f 100644 --- a/i18n/README.nl.md +++ b/i18n/README.nl.md @@ -55,7 +55,7 @@ Supabase is een combinatie van open source tools. We bouwen de functies van Fire **Architectuur** -Supabase is een [gehost platform] (https://app.supabase.com). U kunt zich aanmelden en Supabase gebruiken zonder iets te installeren. +Supabase is een [gehost platform](https://app.supabase.com). U kunt zich aanmelden en Supabase gebruiken zonder iets te installeren. U kunt ook [zelf hosten](https://supabase.com/docs/guides/hosting/overview) en [lokaal ontwikkelen](https://supabase.com/docs/guides/local-development). architectuur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.pl.md b/i18n/README.pl.md index e3536689238..948a1552651 100644 --- a/i18n/README.pl.md +++ b/i18n/README.pl.md @@ -55,7 +55,7 @@ Supabase to połączenie narzędzi open source. Tworzymy funkcje Firebase przy u **Architektura** -Supabase jest [platformą hostowaną] (https://app.supabase.com). Możesz zarejestrować się i zacząć korzystać z Supabase bez instalowania czegokolwiek. +Supabase jest [platformą hostowaną](https://app.supabase.com). Możesz zarejestrować się i zacząć korzystać z Supabase bez instalowania czegokolwiek. Możesz także [self-host](https://supabase.com/docs/guides/hosting/overview) i [rozwijać lokalnie](https://supabase.com/docs/guides/local-development). ![Architektura](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.pt-PT.md b/i18n/README.pt-PT.md index 744c3788744..bc8645f923d 100644 --- a/i18n/README.pt-PT.md +++ b/i18n/README.pt-PT.md @@ -39,7 +39,7 @@ Para ver como contribuir, visite [Getting Started](./DEVELOPERS.md) ## Status - [x] Alfa: Estamos a testar o Supabase com um conjunto fechado de clientes -- [x] Alfa Público: Qualquer pessoa pode inscrever-se em [app.supabase.com] (https://app.supabase.com). Mas vá com calma, ainda há alguns problemas +- [x] Alfa Público: Qualquer pessoa pode inscrever-se em [app.supabase.com](https://app.supabase.com). Mas vá com calma, ainda há alguns problemas - [x] Beta Público: Estável o suficiente para a maioria dos casos de uso não empresarial - [ ] Público: Disponibilidade geral [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)] @@ -55,7 +55,7 @@ O Supabase é uma combinação de ferramentas de código aberto. Estamos a const **Arquitectura** -Supabase é uma [plataforma alojada] (https://app.supabase.com). Pode registar-se e começar a usar o Supabase sem instalar nada. +Supabase é uma [plataforma alojada](https://app.supabase.com). Pode registar-se e começar a usar o Supabase sem instalar nada. Pode também [auto-hospedar](https://supabase.com/docs/guides/hosting/overview) e [desenvolver localmente](https://supabase.com/docs/guides/local-development). ![Arquitectura](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.pt-br.md b/i18n/README.pt-br.md index 78726c4cd7b..0c5ee8cad7b 100644 --- a/i18n/README.pt-br.md +++ b/i18n/README.pt-br.md @@ -7,7 +7,7 @@ # Supabase -[Supabase] (https://supabase.com) é uma alternativa de código aberto ao Firebase. Estamos desenvolvendo os recursos do Firebase usando ferramentas de código aberto de nível empresarial. +[Supabase](https://supabase.com) é uma alternativa de código aberto ao Firebase. Estamos desenvolvendo os recursos do Firebase usando ferramentas de código aberto de nível empresarial. - [x] Banco de dados Postgres hospedado. [Docs](https://supabase.com/docs/guides/database) - [x] Autenticação e autorização. [Docs](https://supabase.com/docs/guides/auth) @@ -39,7 +39,7 @@ Para ver como contribuir, visite [Getting Started](./DEVELOPERS.md) ## Status - [x] Alfa: Estamos testando o Supabase com um conjunto fechado de clientes -- [x] Alfa público: Qualquer pessoa pode se registrar em [app.supabase.com] (https://app.supabase.com). Mas vá com calma, pois há alguns problemas +- [x] Alfa público: Qualquer pessoa pode se registrar em [app.supabase.com](https://app.supabase.com). Mas vá com calma, pois há alguns problemas - [x] Beta público: Estável o suficiente para a maioria dos casos de uso não corporativos - [ ] Público: Disponibilidade geral [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)] @@ -55,8 +55,8 @@ Supabase é uma combinação de ferramentas de código aberto. Estamos desenvolv **Arquitetura** -Supabase é uma [plataforma hospedada] (https://app.supabase.com). Você pode se registrar e começar a usar o Supabase sem instalar nada. -Você também pode [auto-hospedar] (https://supabase.com/docs/guides/hosting/overview) e [desenvolver localmente] (https://supabase.com/docs/guides/local-development). +Supabase é uma [plataforma hospedada](https://app.supabase.com). Você pode se registrar e começar a usar o Supabase sem instalar nada. +Você também pode [auto-hospedar](https://supabase.com/docs/guides/hosting/overview) e [desenvolver localmente](https://supabase.com/docs/guides/local-development). ![Arquitetura](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) diff --git a/i18n/README.sl.md b/i18n/README.sl.md index 44e59308c6f..3554d1bfddb 100644 --- a/i18n/README.sl.md +++ b/i18n/README.sl.md @@ -32,14 +32,14 @@ Za celotno dokumentacijo obiščite [supabase.com/docs](https://supabase.com/doc ## Skupnost in podpora - [Forum skupnosti](https://github.com/supabase/supabase/discussions). Najprimernejši za: pomoč pri gradnji, razpravo o najboljših praksah zbirke podatkov. -- [GitHub Issues] (https://github.com/supabase/supabase/issues). Najprimernejši za: hrošče in napake, na katere naletite pri uporabi zbirke Supabase. +- [GitHub Issues](https://github.com/supabase/supabase/issues). Najprimernejši za: hrošče in napake, na katere naletite pri uporabi zbirke Supabase. - [E-poštna podpora](https://supabase.com/docs/support#business-support). Najboljše za: težave s podatkovno zbirko ali infrastrukturo. - [Discord](https://discord.supabase.com). Najboljši za: izmenjavo aplikacij in druženje s skupnostjo. ## Status - [x] Alfa: Testiramo bazo Supabase z zaprtim naborom strank -- [x] Javna alfa: [app.supabase.com] (https://app.supabase.com). Vendar nas ne obremenjujte, saj je še nekaj pomanjkljivosti +- [x] Javna alfa: [app.supabase.com](https://app.supabase.com). Vendar nas ne obremenjujte, saj je še nekaj pomanjkljivosti - [x] Javna beta različica: Dovolj stabilna za večino primerov uporabe, ki niso povezani s podjetji - [ ] Javna: Splošna razpoložljivost [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)] diff --git a/i18n/README.sv.md b/i18n/README.sv.md index b8c543833f0..2dcebf91d27 100644 --- a/i18n/README.sv.md +++ b/i18n/README.sv.md @@ -7,16 +7,16 @@ # Supabase -[Supabase] (https://supabase.com) är ett alternativ till Firebase med öppen källkod. Vi bygger upp Firebase-funktionerna med hjälp av verktyg för öppen källkod i företagsklass. +[Supabase](https://supabase.com) är ett alternativ till Firebase med öppen källkod. Vi bygger upp Firebase-funktionerna med hjälp av verktyg för öppen källkod i företagsklass. - [x] Hosted Postgres-databas. [Docs](https://supabase.com/docs/guides/database) - [x] Autentisering och auktorisering. [Docs](https://supabase.com/docs/guides/auth) - [x] Automatiskt genererade API:er. - [x] REST. [Docs](https://supabase.com/docs/guides/database/api#rest-api) - [x] GraphQL. [Docs](https://supabase.com/docs/guides/database/api#graphql-api) - - [x] Prenumerationer i realtid. [Dokument] (https://supabase.com/docs/guides/database/api#realtime-api) + - [x] Prenumerationer i realtid. [Dokument](https://supabase.com/docs/guides/database/api#realtime-api) - [x] Funktioner. - - [x] Databasfunktioner. [Dokument] (https://supabase.com/docs/guides/database/functions) + - [x] Databasfunktioner. [Dokument](https://supabase.com/docs/guides/database/functions) - [x] Edge-funktioner [Docs](https://supabase.com/docs/guides/functions) - [x] Lagring av filer. [Docs](https://supabase.com/docs/guides/storage) - [x] Kontrollpanel @@ -25,13 +25,13 @@ ## Dokumentation -Fullständig dokumentation finns på [supabase.com/docs] (https://supabase.com/docs) +Fullständig dokumentation finns på [supabase.com/docs](https://supabase.com/docs) För att se hur man bidrar, besök [Getting Started](./DEVELOPERS.md) ## Gemenskap och stöd -- [Community Forum] (https://github.com/supabase/supabase/discussions). Bäst för: hjälp med att bygga, diskussion om bästa praxis för databaser. +- [Community Forum](https://github.com/supabase/supabase/discussions). Bäst för: hjälp med att bygga, diskussion om bästa praxis för databaser. - [GitHub Issues](https://github.com/supabase/supabase/issues). Bäst för: buggar och fel som du stöter på när du använder Supabase. - [E-postsupport](https://supabase.com/docs/support#business-support). Bäst för: problem med din databas eller infrastruktur. - [Discord](https://discord.supabase.com). Bäst för: att dela med dig av dina applikationer och umgås med gemenskapen. @@ -39,7 +39,7 @@ För att se hur man bidrar, besök [Getting Started](./DEVELOPERS.md) ## Status - [Alpha: Vi testar Supabase med en sluten grupp av kunder -- [x] Public Alpha: Vem som helst kan registrera sig på [app.supabase.com] (https://app.supabase.com). Men var försiktig med oss, det finns några problem +- [x] Public Alpha: Vem som helst kan registrera sig på [app.supabase.com](https://app.supabase.com). Men var försiktig med oss, det finns några problem - [x] Public Beta: Stabil nog för de flesta användningsområden som inte är företag - [ ] Public: Allmän tillgänglighet [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)]] @@ -55,14 +55,14 @@ Supabase är en kombination av verktyg med öppen källkod. Vi bygger funktioner **Arkitektur** -Supabase är en [värdplattform] (https://app.supabase.com). Du kan registrera dig och börja använda Supabase utan att installera något. +Supabase är en [värdplattform](https://app.supabase.com). Du kan registrera dig och börja använda Supabase utan att installera något. Du kan också [självhosta](https://supabase.com/docs/guides/hosting/overview) och [utveckla lokalt](https://supabase.com/docs/guides/local-development). ![Arkitektur](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/) är ett objektrelationellt databassystem med över 30 års aktiv utveckling som har gett det ett gott rykte när det gäller tillförlitlighet, robusthet och prestanda. - [Realtime](https://github.com/supabase/realtime) är en Elixir-server som låter dig lyssna på PostgreSQL-insättningar, uppdateringar och borttagningar med hjälp av websockets. Realtime söker Postgres inbyggda replikeringsfunktionalitet efter databasändringar, omvandlar ändringarna till JSON och sänder sedan JSON via websockets till auktoriserade klienter. -- [PostgREST] (http://postgrest.org/) är en webbserver som omvandlar din PostgreSQL-databas direkt till ett RESTful API +- [PostgREST](http://postgrest.org/) är en webbserver som omvandlar din PostgreSQL-databas direkt till ett RESTful API - [pg_graphql](http://github.com/supabase/pg_graphql/) är ett PostgreSQL-tillägg som exponerar ett GraphQL API - [Storage](https://github.com/supabase/storage-api) tillhandahåller ett RESTful-gränssnitt för hantering av filer som lagras i S3, där Postgres används för att hantera behörigheter. - [postgres-meta](https://github.com/supabase/postgres-meta) är ett RESTful API för hantering av Postgres, så att du kan hämta tabeller, lägga till roller, köra frågor osv. diff --git a/i18n/README.tr.md b/i18n/README.tr.md index d167ec84a14..3689b988b90 100644 --- a/i18n/README.tr.md +++ b/i18n/README.tr.md @@ -7,7 +7,7 @@ # Supabase -[Supabase] (https://supabase.com) açık kaynaklı bir Firebase alternatifidir. Kurumsal düzeyde açık kaynak araçları kullanarak Firebase'in özelliklerini geliştiriyoruz. +[Supabase](https://supabase.com) açık kaynaklı bir Firebase alternatifidir. Kurumsal düzeyde açık kaynak araçları kullanarak Firebase'in özelliklerini geliştiriyoruz. - [x] Barındırılan Postgres Veritabanı. [Dokümanlar](https://supabase.com/docs/guides/database) - [x] Kimlik Doğrulama ve Yetkilendirme. [Dokümanlar](https://supabase.com/docs/guides/auth) diff --git a/i18n/README.uk.md b/i18n/README.uk.md index efd6fc57287..b0b77f34b65 100644 --- a/i18n/README.uk.md +++ b/i18n/README.uk.md @@ -32,14 +32,14 @@ ## Спільнота та підтримка - [Форум спільноти](https://github.com/supabase/supabase/discussions). Найкраще для: допомоги у створенні, обговорення найкращих практик роботи з базами даних. -- [Проблеми GitHub] (https://github.com/supabase/supabase/issues). Найкраще для: помилок і помилок, з якими ви зіткнулися при використанні Supabase. -- [Підтримка електронною поштою] (https://supabase.com/docs/support#business-support). Найкраще для: проблем з вашою базою даних або інфраструктурою. -- [Discord] (https://discord.supabase.com). Найкраще для: обміну вашими додатками та спілкування зі спільнотою. +- [Проблеми GitHub](https://github.com/supabase/supabase/issues). Найкраще для: помилок і помилок, з якими ви зіткнулися при використанні Supabase. +- [Підтримка електронною поштою](https://supabase.com/docs/support#business-support). Найкраще для: проблем з вашою базою даних або інфраструктурою. +- [Discord](https://discord.supabase.com). Найкраще для: обміну вашими додатками та спілкування зі спільнотою. ## Статус - [x] Альфа: Ми тестуємо Supabase із закритим набором клієнтів -- [x] Публічна альфа-версія: Будь-хто може зареєструватися на [app.supabase.com] (https://app.supabase.com). Але будьте обережні з нами, є кілька нюансів +- [x] Публічна альфа-версія: Будь-хто може зареєструватися на [app.supabase.com](https://app.supabase.com). Але будьте обережні з нами, є кілька нюансів - [x] Публічна бета-версія: Достатньо стабільна для більшості непідприємницьких випадків використання - [ ] Загальнодоступна: Загальна доступність [[статус](https://supabase.com/docs/guides/getting-started/features#feature-status)] @@ -55,7 +55,7 @@ Supabase - це комбінація інструментів з відкрит **Архітектура** -Supabase - це [хостингова платформа] (https://app.supabase.com). Ви можете зареєструватися і почати використовувати Supabase без встановлення. +Supabase - це [хостингова платформа](https://app.supabase.com). Ви можете зареєструватися і почати використовувати Supabase без встановлення. Ви також можете [самостійно хостити](https://supabase.com/docs/guides/hosting/overview) і [розробляти локально](https://supabase.com/docs/guides/local-development). ![Архітектура](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) @@ -67,7 +67,7 @@ Supabase - це [хостингова платформа] (https://app.supabase. - [Storage](https://github.com/supabase/storage-api) надає RESTful інтерфейс для керування файлами, що зберігаються у S3, використовуючи Postgres для керування дозволами. - [postgres-meta](https://github.com/supabase/postgres-meta) - RESTful API для керування Postgres, що дозволяє отримувати таблиці, додавати ролі, виконувати запити тощо. - [GoTrue](https://github.com/netlify/gotrue) - API на основі SWT для керування користувачами та випуску токенів SWT. -- [Kong] (https://github.com/Kong/kong) - хмарний API-шлюз. +- [Kong](https://github.com/Kong/kong) - хмарний API-шлюз. #### Клієнтські бібліотеки diff --git a/i18n/README.zh-tw.md b/i18n/README.zh-tw.md index 50d8f26ccb6..9aa8eff8df0 100644 --- a/i18n/README.zh-tw.md +++ b/i18n/README.zh-tw.md @@ -7,7 +7,7 @@ # Supabase -[Supabase](https://supabase.com)是一个开源的Firebase替代品。我们正在使用企业级的开源工具构建Firebase的功能。 +[Supabase](https://supabase.com)是一个开源的 Firebase 替代品。我们正在使用企业级的开源工具构建 Firebase 的功能。 - [x] 托管的 Postgres 数据库。[文档](https://supabase.com/docs/guides/database) - [x] 认证和授权。[文档](https://supabase.com/docs/guides/auth) @@ -21,7 +21,7 @@ - [x] 文件存储。[文件](https://supabase.com/docs/guides/storage) - [x] 仪表板 -! [Supabase Dashboard](https://raw.githubusercontent.com/supabase/supabase/master/apps/www/public/images/github/supabase-dashboard.png) +![Supabase Dashboard](https://raw.githubusercontent.com/supabase/supabase/master/apps/www/public/images/github/supabase-dashboard.png) ## 文档 @@ -39,9 +39,9 @@ ## 状态 - [x] 阿尔法:我们正在与一组封闭的客户测试 Supabase。 -- [x] 公开阿尔法:任何人都可以在[app.supabase.com](https://app.supabase.com)上注册。但请对我们宽容一些,有一些小问题。 +- [x] 公开阿尔法:任何人都可以在[app.supabase.com](https://app.supabase.com)上注册。但请对我们宽容一些,有一些小问题。 - [x] 公开测试版:足够稳定,适合大多数非企业使用的情况。 -- [] 公开:普遍可用 [[状态](https://supabase.com/docs/guides/getting-started/features#feature-status)] +- [] 公开:普遍可用 [状态](https://supabase.com/docs/guides/getting-started/features#feature-status) 我们目前正处于公开测试阶段。请关注本软件库的 "发布",以获得重大更新的通知。 @@ -55,10 +55,10 @@ Supabase 是一个开源工具的组合。我们正在使用企业级的开源 **架构** -Supabase 是一个[托管平台](https://app.supabase.com)。你可以注册并开始使用Supabase,无需安装任何东西。 +Supabase 是一个[托管平台](https://app.supabase.com)。你可以注册并开始使用 Supabase,无需安装任何东西。 你也可以[自我托管](https://supabase.com/docs/guides/hosting/overview)和[本地开发](https://supabase.com/docs/guides/local-development)。 -! [架构](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) +![架构](https://github.com/supabase/supabase/blob/master/apps/docs/public/img/supabase-architecture.png) - [PostgreSQL](https://www.postgresql.org/)是一个对象关系型数据库系统,经过 30 多年的积极开发,它在可靠性、功能稳健性和性能方面赢得了良好的声誉。 - [Realtime](https://github.com/supabase/realtime)是一个 Elixir 服务器,允许你使用 websockets 监听 PostgreSQL 的插入、更新和删除。Realtime 对 Postgres 内置的复制功能进行投票,以了解数据库的变化,将变化转换为 JSON,然后通过 websockets 将 JSON 广播给授权客户。 @@ -77,7 +77,7 @@ Supabase 是一个[托管平台](https://app.supabase.com)。你可以注册 语言 客户端 - 特征-客户端(捆绑在Supabase客户端中) + 特征-客户端(捆绑在Supabase客户端中) @@ -238,10 +238,10 @@ Supabase 是一个[托管平台](https://app.supabase.com)。你可以注册 - [Persian / فارسی](/i18n/README.fa.md) - [Polish / Polski](/i18n/README.pl.md) - [葡萄牙语 / Português](/i18n/README.pt.md) -- [葡萄牙语(巴西)/Português Brasileiro](/i18n/README.pt-br.md) -- [Romanian / Română] (/i18n/README.ro.md) +- [葡萄牙语(巴西)/Português Brasileiro](/i18n/README.pt-br.md) +- [Romanian / Română](/i18n/README.ro.md) - [俄语 / Pусский](/i18n/README.ru.md) -- [塞尔维亚语 / Srpski] (/i18n/README.sr.md) +- [塞尔维亚语 / Srpski](/i18n/README.sr.md) - [Sinhala / සිංහල](/i18n/README.si.md) - [西班牙语 / Español](/i18n/README.es.md) - [Simplified Chinese / 简体中文](/i18n/README.zh-cn.md) @@ -257,4 +257,4 @@ Supabase 是一个[托管平台](https://app.supabase.com)。你可以注册 ## 赞助商 -[![新赞助商](https://user-images.githubusercontent.com/10214025/90518111-e74bbb00-e198-11ea-8f88-c9e3c1aa4b5b.png)](https://github.com/sponsors/supabase) +[![新赞助商](https://user-images.githubusercontent.com/10214025/90518111-e74bbb00-e198-11ea-8f88-c9e3c1aa4b5b.png)](https://github.com/sponsors/supabase) diff --git a/package-lock.json b/package-lock.json index 228f176bb45..71b03870568 100644 --- a/package-lock.json +++ b/package-lock.json @@ -314,6 +314,7 @@ "version": "0.0.3", "license": "MIT", "dependencies": { + "@code-hike/mdx": "^0.8.3", "@heroicons/react": "^1.0.6", "@mdx-js/loader": "^2.1.5", "@mdx-js/react": "^2.1.5", @@ -355,6 +356,7 @@ "remark": "^14.0.2", "remark-gfm": "^3.0.1", "remark-html": "^15.0.1", + "shared-data": "*", "swiper": "^6.5.0", "swr": "^0.5.4", "typescript": "^5.0.4", diff --git a/apps/docs/styles/code-hike.scss b/packages/config/code-hike.scss similarity index 100% rename from apps/docs/styles/code-hike.scss rename to packages/config/code-hike.scss diff --git a/apps/docs/code-hike.theme.json b/packages/config/code-hike.theme.json similarity index 100% rename from apps/docs/code-hike.theme.json rename to packages/config/code-hike.theme.json diff --git a/apps/www/data/Pricing.json b/packages/shared-data/Pricing.json similarity index 81% rename from apps/www/data/Pricing.json rename to packages/shared-data/Pricing.json index ed7b1fe6b56..b24b43f883f 100644 --- a/apps/www/data/Pricing.json +++ b/packages/shared-data/Pricing.json @@ -8,17 +8,19 @@ "tooltips": { "main": "A Postgres database with no restrictions? You get it. No pseudo limited users, you are the postgres root user. No caveats." }, - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, { "title": "Unlimited API requests", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, @@ -27,9 +29,10 @@ "tooltips": { "main": "Billing is based on the average database size in GB throughout the billing period." }, - "tiers": { + "plans": { "free": "500 MB", "pro": "8 GB, then $0.125 per GB", + "team": "8 GB, then $0.125 per GB", "enterprise": "Unlimited" } }, @@ -37,11 +40,13 @@ "title": "Automatic backups", "tooltips": { "main": "Backups are entire copies of your database that can be restored in the future.", - "pro": "7 days of backup (if > 1TB, contact for Enterprise pricing)" + "pro": "7 days of backup (if > 1TB, contact for Enterprise pricing)", + "team": "14 days of backup (if > 1TB, contact for Enterprise pricing)" }, - "tiers": { + "plans": { "free": false, "pro": "7 days", + "team": "14 days", "enterprise": "Custom" } }, @@ -49,11 +54,13 @@ "title": "Point in time recovery", "tooltips": { "main": "PITR cannot be applied retroactively, projects can only be rolled back to the point from which PITR has been applied.", - "pro": "$100 per 7 days. If > 28 day rollback period, contact enterprise" + "pro": "$100 per 7 days. If > 28 day rollback period, contact enterprise", + "team": "$100 per 7 days. If > 28 day rollback period, contact enterprise" }, - "tiers": { + "plans": { "free": false, "pro": "$100 per 7 days", + "team": "$100 per 7 days", "enterprise": true } }, @@ -62,9 +69,10 @@ "tooltips": { "main": "Projects that have no activity or API requests will be paused. They can be reactivated via the dashboard" }, - "tiers": { + "plans": { "free": "After 1 inactive week", "pro": "Never", + "team": "Never", "enterprise": "Never" } }, @@ -73,9 +81,10 @@ "tooltips": { "main": "Billing is based on the total sum of outgoing traffic of your database in GB throughout your billing period. Only download operations are counted towards the limit" }, - "tiers": { + "plans": { "free": "2GB", "pro": "50 GB, then $0.09 per GB", + "team": "50 GB, then $0.09 per GB", "enterprise": "Unlimited" } } @@ -88,9 +97,10 @@ { "title": "Total Users", "tooltips": { "main": "The maximum number of users your project can have" }, - "tiers": { + "plans": { "free": "Unlimited", "pro": "Unlimited", + "team": "Unlimited", "enterprise": "Unlimited" } }, @@ -99,74 +109,83 @@ "tooltips": { "main": "Distinct users requesting your API throughout the billing period." }, - "tiers": { + "plans": { "free": "50,000", "pro": "100,000, then $0.00325 per MAU", + "team": "100,000, then $0.00325 per MAU", "enterprise": "Unlimited" } }, { "title": "Social OAuth providers", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, { "title": "Custom SMTP server", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, { "title": "Remove Supabase branding from emails", - "tiers": { + "plans": { "free": false, "pro": true, + "team": true, "enterprise": true } }, { "title": "Enterprise OAuth providers", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "Audit trails", - "tiers": { + "plans": { "free": "1 hour", "pro": "7 days", + "team": "28 days", "enterprise": true } }, { "title": "Supabase Auth emails", "tooltips": { "main": "Rate limits do not apply to Custom SMTP" }, - "tiers": { + "plans": { "free": "30 / hour", "pro": "100 / hour", + "team": "100 / hour", "enterprise": "Contact Us" } }, { "title": "Single Sign-On (SAML 2.0)", - "tiers": { + "plans": { "free": false, "pro": "50 free, then $0.015 per MAU", + "team": "50 free, then $0.015 per MAU", "enterprise": "Contact Us" } }, { "title": "Advanced security features", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": "Contact Us" } } @@ -182,9 +201,10 @@ "tooltips": { "main": "The sum of all objects' size in your storage buckets." }, - "tiers": { + "plans": { "free": "1 GB", "pro": "100 GB, then $0.021 per GB", + "team": "100 GB, then $0.021 per GB", "enterprise": "Unlimited" } }, @@ -193,26 +213,29 @@ "tooltips": { "main": "Total sum of outgoing traffic (egress) from your storage buckets, only download operations are counted." }, - "tiers": { + "plans": { "free": "2 GB", "pro": "200 GB, then $0.09 per GB", + "team": "200 GB, then $0.09 per GB", "enterprise": "Unlimited" } }, { "title": "Custom access controls", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, { "title": "Max file upload size", "tooltips": { "main": "You can change the upload size in the dashboard" }, - "tiers": { + "plans": { "free": "50MB", "pro": "5GB", + "team": "5GB", "enterprise": "Unlimited" } }, @@ -221,9 +244,11 @@ "tooltips": { "main": "Distinct count of all images that were transformed in the billing period, ignoring any transformations." }, - "tiers": { + "plans": { "free": false, - "pro": "100 origin images, then $5 per 1000 origin images" + "pro": "100 origin images, then $5 per 1000 origin images", + "team": "100 origin images, then $5 per 1000 origin images", + "enterprise": "Unlimited" } } ] @@ -238,17 +263,19 @@ "main": "Billing is based on the sum of all invocations, independent of response status, throughout your billing period." }, "main": "Billing is based on the sum of all invocations, independent of response status, throughout your billing period.", - "tiers": { + "plans": { "free": "500K/month", "pro": "2 Million, then $2 per 1 Million", + "team": "2 Million, then $2 per 1 Million", "enterprise": "Unlimited" } }, { "title": "Script size", - "tiers": { + "plans": { "free": "2 MB", "pro": "10 MB", + "team": "10 MB", "enterprise": "Unlimited" } }, @@ -257,9 +284,10 @@ "tooltips": { "main": "Billing is based on the maximum amount of functions at any point in time throughout your billing period." }, - "tiers": { + "plans": { "free": "10", "pro": "100, then $10 per additional 100", + "team": "100, then $10 per additional 100", "enterprise": "Unlimited" } } @@ -271,9 +299,10 @@ "features": [ { "title": "Postgres Changes", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, @@ -282,9 +311,10 @@ "tooltips": { "main": "We only charge for successful connections - not connection attempts!" }, - "tiers": { + "plans": { "free": "200", "pro": "500, then $10 per 1000", + "team": "500, then $10 per 1000", "enterprise": "Unlimited concurrent connections and volume discount" } }, @@ -293,17 +323,19 @@ "tooltips": { "main": "Billing is based on the total sum of Realtime messages throughout your billing period." }, - "tiers": { + "plans": { "free": "2 Million", "pro": "5 Million, then $2.50 per Million", + "team": "5 Million, then $2.50 per Million", "enterprise": "Volume discounts on messages" } }, { "title": "Max Message Size", - "tiers": { + "plans": { "free": "250 KB", "pro": "3 MB", + "team": "3 MB", "enterprise": "Custom" } } @@ -315,25 +347,28 @@ "features": [ { "title": "Team members", - "tiers": { + "plans": { "free": "Unlimited", "pro": "Unlimited", + "team": "Unlimited", "enterprise": "Unlimited" } }, { "title": "Access controls", - "tiers": { + "plans": { "free": "Coming soon", "pro": "Coming soon", + "team": true, "enterprise": true } }, { "title": "Audit trails", - "tiers": { + "plans": { "free": false, "pro": false, + "team": true, "enterprise": true } } @@ -345,73 +380,82 @@ "features": [ { "title": "On Premises / BYO cloud", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "Log retention (API & Database)", - "tiers": { + "plans": { "free": "1 day", "pro": "7 days", + "team": "28 days", "enterprise": "90 days" } }, { "title": "Log drain", - "tiers": { + "plans": { "free": false, "pro": false, + "team": "Coming soon", "enterprise": "Coming soon" } }, { "title": "Metrics endpoint", - "tiers": { + "plans": { "free": false, "pro": true, + "team": true, "enterprise": true } }, { "title": "SOC2", - "tiers": { + "plans": { "free": false, "pro": false, + "team": true, "enterprise": true } }, { "title": "SSO", - "tiers": { + "plans": { "free": false, "pro": false, + "team": "Contact Us", "enterprise": "Contact Us" } }, { "title": "99.9% SLA", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "Access Roles", - "tiers": { + "plans": { "free": "Owner, Developer", "pro": "Owner, Developer", + "team": "Additional owner(s), admin, read-only, billing admin, custom", "enterprise": "Additional owner(s), admin, read-only, billing admin, custom" } }, { "title": "Vanity URLs", - "tiers": { + "plans": { "free": false, "pro": true, + "team": true, "enterprise": true } }, @@ -420,9 +464,10 @@ "tooltips": { "enterprise": "Volume discounts available." }, - "tiers": { + "plans": { "free": false, "pro": "$10 per domain per month per project add on", + "team": "$10 per domain per month per project add on", "enterprise": "1, additional $10/domain/month" } } @@ -434,57 +479,64 @@ "features": [ { "title": "Community support", - "tiers": { + "plans": { "free": true, "pro": true, + "team": true, "enterprise": true } }, { "title": "Email support", - "tiers": { + "plans": { "free": false, "pro": true, + "team": true, "enterprise": true } }, { "title": "Email support SLA", - "tiers": { + "plans": { "free": false, "pro": false, + "team": true, "enterprise": true } }, { "title": "Designated support", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "On Boarding Support", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "Designated customer success engineer ", - "tiers": { + "plans": { "free": false, "pro": false, + "team": false, "enterprise": true } }, { "title": "Security Questionnaire Help", - "tiers": { + "plans": { "free": false, "pro": false, + "team": true, "enterprise": true } } diff --git a/packages/shared-data/index.ts b/packages/shared-data/index.ts index 37d9a59f2a2..c55fe15a7b7 100644 --- a/packages/shared-data/index.ts +++ b/packages/shared-data/index.ts @@ -1,4 +1,6 @@ import tweets from './tweets' import logConstants from './logConstants' +import { plans, PricingInformation } from './plans' -export { tweets, logConstants } +export { tweets, logConstants, plans } +export type { PricingInformation } diff --git a/packages/shared-data/package.json b/packages/shared-data/package.json index 3a2165ffed7..9dd0d49e5be 100644 --- a/packages/shared-data/package.json +++ b/packages/shared-data/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "description": "Data shared between Supabase apps", "main": "./index.ts", + "types": "./index.ts", "scripts": {}, "author": "", "license": "MIT" diff --git a/packages/shared-data/plans.ts b/packages/shared-data/plans.ts new file mode 100644 index 00000000000..0124e3465e6 --- /dev/null +++ b/packages/shared-data/plans.ts @@ -0,0 +1,117 @@ +export interface PricingInformation { + id: string + name: string + nameBadge?: string + costUnit?: string + href: string + priceLabel?: string + priceMonthly: number | string + warning?: string + description: string + preface: string + features: string[] + footer?: string + cta: string +} + +export const plans: PricingInformation[] = [ + { + id: 'tier_free', + name: 'Free', + nameBadge: '', + costUnit: '/ month', + href: 'https://supabase.com/dashboard/new/new-project', + priceLabel: '', + priceMonthly: 0, + warning: 'Limit of 2 free projects', + description: 'Perfect for passion projects & simple websites.', + preface: 'Get started with:', + features: [ + 'Unlimited API requests', + 'Social OAuth providers', + 'Up to 500MB database space', + 'Up to 1GB file storage', + 'Up to 2GB bandwidth', + 'Up to 50MB file uploads', + 'Up to 50,000 monthly active users', + 'Up to 500K Edge Function invocations', + 'Up to 200 concurrent Realtime connections', + 'Up to 2 million Realtime messages', + '1-day log retention', + 'Community support', + ], + footer: 'Free projects are paused after 1 week of inactivity.', + cta: 'Get Started', + }, + { + id: 'tier_pro', + name: 'Pro', + nameBadge: '', + costUnit: '/ month', + href: 'https://supabase.com/dashboard/new/new-project', + priceLabel: 'From', + warning: 'Usage-based plan', + priceMonthly: 25, + description: 'For production applications with the option to scale.', + features: [ + 'No project pausing', + 'Daily backups stored for 7 days', + '8GB database space included', + '100GB file storage included', + '50GB bandwidth included', + '5GB file uploads included', + '100,000 monthly active users included', + '2M Edge Function invocations included', + '500 concurrent Realtime connections included', + '5 million Realtime messages included', + '7-day log retention', + 'Email support', + ], + footer: + 'Your cost control settings determine if you allow over-usage.', + preface: 'Everything in the Free plan, plus:', + cta: 'Get Started', + }, + { + id: 'tier_team', + name: 'Team', + nameBadge: 'New', + costUnit: '/ month', + href: 'https://forms.supabase.com/team', + priceLabel: 'From', + warning: 'Usage-based plan', + priceMonthly: 599, + description: 'Collaborate with different permissions and access patterns.', + features: [ + 'Additional Organization member roles', + 'Daily backups stored for 14 days', + 'Standardised Security Questionnaire', + 'SOC2', + 'SSO for Supabase Dashboard', + 'Priority email support & SLAs', + '28-day log retention', + ], + footer: 'Additional fees apply for usage beyond included usage.', + preface: 'Everything in the Pro plan, plus:', + cta: 'Contact Us', + }, + { + id: 'tier_enterprise', + name: 'Enterprise', + href: 'https://forms.supabase.com/enterprise', + description: 'For large-scale applications managing serious workloads.', + features: [ + `Designated Support manager & SLAs`, + `Enterprise OAuth providers`, + `SSO/SAML`, + `On-premise support`, + `24×7×365 premium enterprise support`, + `Private Slack channel`, + ], + priceLabel: '', + priceMonthly: 'Contact us', + preface: '', + footer: '', + cta: 'Contact Us', + }, +] diff --git a/packages/shared-data/tsconfig.json b/packages/shared-data/tsconfig.json new file mode 100644 index 00000000000..cd6c94d6e8b --- /dev/null +++ b/packages/shared-data/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "tsconfig/react-library.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"] +} diff --git a/packages/ui/src/components/Command/Command.icons.tsx b/packages/ui/src/components/Command/Command.icons.tsx index 22e2a37a176..9d0914765b0 100644 --- a/packages/ui/src/components/Command/Command.icons.tsx +++ b/packages/ui/src/components/Command/Command.icons.tsx @@ -7,24 +7,22 @@ interface AiIconProps { export const AiIcon = ({ className = 'text-brand-900' }: AiIconProps) => ( ) diff --git a/studio/components/interfaces/Billing/Billing.constants.tsx b/studio/components/interfaces/Billing/Billing.constants.tsx index 7661fa41f61..5b55dbb1ba8 100644 --- a/studio/components/interfaces/Billing/Billing.constants.tsx +++ b/studio/components/interfaces/Billing/Billing.constants.tsx @@ -1,22 +1,5 @@ import { IconArchive, IconCode, IconDatabase, IconKey, IconZap } from 'ui' -export const CANCELLATION_REASONS = [ - 'Pricing', - "My project isn't getting traction", - 'Poor customer service', - 'Missing feature', - "I didn't see the value", - "Supabase didn't meet my needs", - 'Dashboard is too complicated', - 'Postgres is too complicated', - 'Problem not solved', - 'Bug issues', - 'I decided to use something else', - 'My work has finished/discontinued', - 'I’m migrating to/starting a new project', - 'None of the above', -] - export const USAGE_BASED_PRODUCTS = [ { title: 'Database', diff --git a/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx b/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx index 306b05142f0..b488e3011b7 100644 --- a/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx +++ b/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx @@ -8,11 +8,11 @@ import { Button, Form, Input, Modal, IconArrowLeft, Alert } from 'ui' import { useFlag, useStore } from 'hooks' import { post, patch } from 'lib/common/fetch' import { API_URL, PROJECT_STATUS } from 'lib/constants' -import { CANCELLATION_REASONS } from '../Billing.constants' import { UpdateSuccess } from '../' import { SubscriptionPreview } from '../Billing.types' import { StripeSubscription } from 'components/interfaces/Billing' import HCaptcha from '@hcaptcha/react-hcaptcha' +import { CANCELLATION_REASONS } from 'components/interfaces/BillingV2/Billing.constants' interface ExitSurveyProps { freeTier: any diff --git a/studio/components/interfaces/Billing/PlanSelection/PlanSelection.tsx b/studio/components/interfaces/Billing/PlanSelection/PlanSelection.tsx index be18a54c621..a063a545588 100644 --- a/studio/components/interfaces/Billing/PlanSelection/PlanSelection.tsx +++ b/studio/components/interfaces/Billing/PlanSelection/PlanSelection.tsx @@ -5,6 +5,7 @@ import { Transition } from '@headlessui/react' import PlanCard from './Plans/PlanCard' import { formatTierOptions } from './PlanSelection.utils' import { Button, IconExternalLink } from 'ui' +import PlanCardEnterprise from './Plans/PlanCardEnterprise' interface Props { visible: boolean @@ -16,11 +17,7 @@ interface Props { const PlanSelection: FC = ({ visible, tiers, currentPlan, onSelectPlan }) => { const formattedTiers = formatTierOptions(tiers) - // [Kevin] TODO Remove after team plan is generally available - const gridCols = - formattedTiers.length === 3 - ? 'gap-8 lg:grid-cols-3' - : 'gap-4 lg:grid-cols-3 xl:grid-cols-billingWithTeam' + const enterprisePlan = formattedTiers.find((it) => it.name === 'Enterprise')! return ( = ({ visible, tiers, currentPlan, onSelectPlan }) >

Change your project's subscription

-
- {formattedTiers.map((plan) => { - return ( - onSelectPlan(plan)} - /> - ) - })} +
+ {formattedTiers + .filter((it) => it.name !== 'Enterprise') + .map((plan) => { + return ( + onSelectPlan(plan)} + /> + ) + })} +
+
+ onSelectPlan(enterprisePlan)} + />
diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx index faa1ba68311..444084b9579 100644 --- a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCTAButton.tsx @@ -20,13 +20,23 @@ const PlanCTAButton = ({ plan, currentPlan, onSelectPlan }: PlanCTAButtonProps) const isTeamTier = currentPlan?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM const getButtonType = (plan: any, currentPlan: any) => { + if ( + currentPlan.supabase_prod_id !== PRICING_TIER_PRODUCT_IDS.ENTERPRISE && + plan.name === 'Enterprise' + ) { + return 'default' + } + if (['Free tier', 'Free plan'].includes(plan.name)) { // Free is always default return 'default' } else if (currentPlan.prod_id === STRIPE_PRODUCT_IDS.FREE) { // If the current plan is free, other plans are primary return 'primary' - } else if (currentPlan.prod_id === STRIPE_PRODUCT_IDS.TEAM && !['Team tier', 'Team plan'].includes(plan.name)) { + } else if ( + currentPlan.prod_id === STRIPE_PRODUCT_IDS.TEAM && + !['Team tier', 'Team plan'].includes(plan.name) + ) { // Non-free plans are default (pro), when team plan is selected return 'default' } @@ -60,18 +70,10 @@ const PlanCTAButton = ({ plan, currentPlan, onSelectPlan }: PlanCTAButtonProps) } } - if (plan.id === STRIPE_PRODUCT_IDS.TEAM) { - if (currentPlan.prod_id === STRIPE_PRODUCT_IDS.TEAM) { - return 'Edit plan configuration' - } else if ( - [STRIPE_PRODUCT_IDS.FREE, STRIPE_PRODUCT_IDS.PRO, STRIPE_PRODUCT_IDS.PAYG].includes( - currentPlan.prod_id - ) - ) { - return 'Upgrade to Team' - } else { - return 'Contact sales' - } + if (plan.id === STRIPE_PRODUCT_IDS.TEAM && currentPlan.prod_id === STRIPE_PRODUCT_IDS.TEAM) { + return 'Edit plan configuration' + } else { + return 'Contact sales' } } @@ -103,6 +105,18 @@ const PlanCTAButton = ({ plan, currentPlan, onSelectPlan }: PlanCTAButtonProps) ) } + if (!isTeamTier && plan.name === 'Team plan') { + return ( + + + + + + ) + } + return (
diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCard.tsx b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCard.tsx index 8804f44446b..74102beab90 100644 --- a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCard.tsx +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCard.tsx @@ -1,8 +1,7 @@ -import { PRICING_TIER_PRODUCT_IDS, STRIPE_PRODUCT_IDS } from 'lib/constants' +import { STRIPE_PRODUCT_IDS } from 'lib/constants' import { FC } from 'react' import { IconCheck } from 'ui' -import { useFlag } from 'hooks' import PlanCTAButton from './PlanCTAButton' import { PRICING_META } from './Plans.Constants' @@ -13,12 +12,7 @@ interface Props { } const PlanCard: FC = ({ plan, currentPlan, onSelectPlan }) => { - // Team tier is enabled when the flag is turned on OR the user is already on the team tier (manually assigned by us) - const teamTierEnabled = - useFlag('teamTier') || currentPlan?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM - const planMeta = PRICING_META[plan.id] - const isEnterprise = plan.id === 'Enterprise' const isCurrentPlan = plan.id === currentPlan?.prod_id || (plan.id === STRIPE_PRODUCT_IDS.PRO && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO) || @@ -26,35 +20,12 @@ const PlanCard: FC = ({ plan, currentPlan, onSelectPlan }) => { return (
-
-
+
+
-

- {planMeta.name} -

+

{planMeta.name}

{isCurrentPlan ? (
Current plan @@ -66,16 +37,7 @@ const PlanCard: FC = ({ plan, currentPlan, onSelectPlan }) => { )}

{planMeta.description}

-
+
{planMeta.priceMonthly !== undefined ? ( <>

Starting from

@@ -92,15 +54,9 @@ const PlanCard: FC = ({ plan, currentPlan, onSelectPlan }) => { )}
-
+

{planMeta.preface}

-
    +
      {planMeta.features.map((feature) => (
    • @@ -116,35 +72,34 @@ const PlanCard: FC = ({ plan, currentPlan, onSelectPlan }) => {
- {!isEnterprise && ( -
-
-

{planMeta.scale}

- {planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO && ( -
-

- Need more? Turn off your spend cap to Pay As You Grow -

-

- Additional fees apply for spend beyond the limits above -

{' '} -
- )} +
+
+

{planMeta.scale}

- {planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PAYG && ( -
-

Spend cap is currently disabled

-

- You will be charged for usage beyond the plan limits -

{' '} -
- )} -
+ {planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO && ( +
+

+ Need more? Turn off your spend cap to Pay As You Grow +

+

+ Additional fees apply for spend beyond the limits above +

{' '} +
+ )} - + {planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PAYG && ( +
+

Spend cap is currently disabled

+

+ You will be charged for usage beyond the plan limits +

{' '} +
+ )}
- )} + + +
) } diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCardEnterprise.tsx b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCardEnterprise.tsx new file mode 100644 index 00000000000..a586e9b6d27 --- /dev/null +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/PlanCardEnterprise.tsx @@ -0,0 +1,64 @@ +import { STRIPE_PRODUCT_IDS } from 'lib/constants' +import { FC } from 'react' +import { IconCheck } from 'ui' + +import PlanCTAButton from './PlanCTAButton' +import { PRICING_META } from './Plans.Constants' + +interface Props { + plan: any + currentPlan: any + onSelectPlan: () => void +} + +const PlanCardEnterprise: FC = ({ plan, currentPlan, onSelectPlan }) => { + const planMeta = PRICING_META[plan.id] + const isCurrentPlan = + plan.id === currentPlan?.prod_id || + (plan.id === STRIPE_PRODUCT_IDS.PRO && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO) || + (plan.id === STRIPE_PRODUCT_IDS.PRO && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PAYG) + + return ( +
+
+
+
+
+

{planMeta.name}

+ {isCurrentPlan ? ( +
+ Current plan +
+ ) : planMeta.new ? ( +
New
+ ) : ( + <> + )} +
+

{planMeta.description}

+
+ +
+
+
+

{planMeta.preface}

+
    + {planMeta.features.map((feature) => ( +
  • +
  • + ))} +
+
+
+
+
+ ) +} + +export default PlanCardEnterprise diff --git a/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.Constants.ts b/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.Constants.ts index 2bc41b3cdee..15f93675fc4 100644 --- a/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.Constants.ts +++ b/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.Constants.ts @@ -1,11 +1,7 @@ import { STRIPE_PRODUCT_IDS } from 'lib/constants' -/** - * @mildtomato same plan metadata is also in /www website - * would be good if this constant was shared across apps - * - * https://github.com/supabase/supabase/blob/master/studio/components/interfaces/Billing/PlanSelection/Plans/Plans.Constants.ts - */ +// This file will get deleted soon and superseded by components in BillingV2/* + export const PRICING_META = { [STRIPE_PRODUCT_IDS.FREE]: { id: 'tier_free', @@ -13,18 +9,20 @@ export const PRICING_META = { name: 'Free', description: 'Perfect for passion projects & simple websites.', priceMonthly: 0, - priceUnit: 'per month per project', + priceUnit: '/ month', warning: 'Limit of 2 free projects', preface: 'Get started with:', features: [ + 'Unlimited API requests', 'Social OAuth providers', - 'Up to 500MB database & 1GB file storage', + 'Up to 500MB database space', + 'Up to 1GB file storage', 'Up to 2GB bandwidth', 'Up to 50MB file uploads', - '50,000 monthly active users', + 'Up to 50,000 monthly active users', 'Up to 500K Edge Function invocations', - '200 concurrent Realtime connections', - '2 million Realtime messages', + 'Up to 200 concurrent Realtime connections', + 'Up to 2 million Realtime messages', '1-day log retention', 'Community support', ], @@ -36,21 +34,22 @@ export const PRICING_META = { name: 'Pro', description: 'For production applications with the option to scale.', priceMonthly: 25, - priceUnit: 'per month per project', - warning: '+ any additional usage', + priceUnit: '/ month', + warning: 'Usage-based plan', preface: 'Everything in the Free plan, plus:', features: [ 'No project pausing', - '8GB database & 100GB file storage', - '50GB bandwidth', - '5GB file uploads', - '100,000 monthly active users', - '2M Edge Function invocations', - '500 concurrent Realtime connections', - '5 million Realtime messages', + 'Daily backups stored for 7 days', + '8GB database space included', + '100GB file storage included', + '50GB bandwidth included', + '5GB file uploads included', + '100,000 monthly active users included', + '2M Edge Function invocations included', + '500 concurrent Realtime connections included', + '5 million Realtime messages included', '7-day log retention', 'Email support', - 'Daily backups', ], }, [STRIPE_PRODUCT_IDS.TEAM]: { @@ -59,20 +58,17 @@ export const PRICING_META = { name: 'Team', description: 'Collaborate with different permissions and access patterns.', priceMonthly: 599, - priceUnit: 'per month per organization', - warning: '+ usage', - preface: 'The following features will apply to all projects within the organization:', + priceUnit: '/ month', + warning: 'Usage-based plan', + preface: 'Everything in the Pro plan, plus:', features: [ - 'Usage-based pricing', - '100,000 monthly active users included', - 'Organization member roles (ABAC)', + 'Additional Organization member roles', + 'Daily backups stored for 14 days', 'Standardised Security Questionnaire', 'SOC2', 'SSO for Supabase Dashboard', 'Priority email support & SLAs', - '1 XS compute instance', - '14 day backups', - '28 day log retention', + '28-day log retention', ], }, Enterprise: { @@ -85,14 +81,10 @@ export const PRICING_META = { features: [ `Designated Support manager & SLAs`, `Enterprise OAuth providers`, - `SSO/ SAML`, - `SOC2`, - `Custom contracts & invoicing`, + `SSO/SAML`, `On-premise support`, `24×7×365 premium enterprise support`, - `Custom Security questionnaires`, `Private Slack channel`, - `Uptime SLA`, ], }, } diff --git a/studio/components/interfaces/Billing/TeamUpgrade.tsx b/studio/components/interfaces/Billing/TeamUpgrade.tsx index e5902fc7963..f0e83f6bb5f 100644 --- a/studio/components/interfaces/Billing/TeamUpgrade.tsx +++ b/studio/components/interfaces/Billing/TeamUpgrade.tsx @@ -48,10 +48,8 @@ const TeamUpgrade = ({ const { app, ui } = useStore() const router = useRouter() - // Team tier is enabled when the flag is turned on OR the user is already on the team tier (manually assigned by us) - const userIsOnTeamTier = - currentSubscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM - const teamTierEnabled = useFlag('teamTier') || userIsOnTeamTier + // Team tier is enabled when the user is already on the team tier (manually assigned by us) + const teamTierEnabled = currentSubscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM const [captchaToken, setCaptchaToken] = useState(null) const captchaRef = useRef(null) diff --git a/studio/components/interfaces/BillingV2/Billing.constants.ts b/studio/components/interfaces/BillingV2/Billing.constants.ts index 0b7203cbf01..519a1ca2afc 100644 --- a/studio/components/interfaces/BillingV2/Billing.constants.ts +++ b/studio/components/interfaces/BillingV2/Billing.constants.ts @@ -1 +1,18 @@ export const USAGE_APPROACHING_THRESHOLD = 0.8 + +export const CANCELLATION_REASONS = [ + 'Pricing', + "My project isn't getting traction", + 'Poor customer service', + 'Missing feature', + "I didn't see the value", + "Supabase didn't meet my needs", + 'Dashboard is too complicated', + 'Postgres is too complicated', + 'Problem not solved', + 'Bug issues', + 'I decided to use something else', + 'My work has finished/discontinued', + 'I’m migrating to/starting a new project', + 'None of the above', +] diff --git a/studio/components/interfaces/BillingV2/Subscription/BillingBreakdown.tsx b/studio/components/interfaces/BillingV2/Subscription/BillingBreakdown.tsx index eb53e89ba8b..9296e821a56 100644 --- a/studio/components/interfaces/BillingV2/Subscription/BillingBreakdown.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/BillingBreakdown.tsx @@ -42,7 +42,7 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => { const currentPlan = subscription?.plan const isUsageBillingEnabled = subscription?.usage_billing_enabled const [usageFees, fixedFees] = partition(upcomingInvoice?.lines ?? [], (item) => item.usage_based) - const totalUsageFees = usageFees.reduce((a, b) => a + b.amount, 0) + const totalUsageFees = Number(usageFees.reduce((a, b) => a + b.amount, 0).toFixed(2)) const hasExceededAnyLimits = isUsageBillingEnabled === false && @@ -77,13 +77,14 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => { {isUsageBillingEnabled ? (

Your plan includes a limited amount of included usage. If the usage on your project - exceeds these quotas, your subscription will be charged for the extra usage. + exceeds these quotas, your subscription will be charged for the overage. It may take + up to 24 hours for usage stats to update.

) : (

Your plan includes a limited amount of included usage. If the usage on your project exceeds these quotas, you may experience restrictions, as you are currently not billed - for overusage. + for overage. It may take up to 24 hours for usage stats to update.

)} @@ -96,7 +97,7 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => { - - + + +
- {!isTeamTierEnabled &&
} +
+
    + {plan.features.map((feature) => ( +
  • +
  • + ))} +
-
    - {plan.features.map((feature) => ( -
  • -
    -
    -

    {feature}

    -
  • - ))} -
+ + + +
) } diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/ExitSurveyModal.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/ExitSurveyModal.tsx index eae5482a505..27346959ee4 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/ExitSurveyModal.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/ExitSurveyModal.tsx @@ -10,8 +10,8 @@ import { includes, without } from 'lodash' import { useRouter } from 'next/router' import { useReducer, useRef, useState } from 'react' import { Button, Input, Modal } from 'ui' -import { CANCELLATION_REASONS } from './Tier.constants' import ProjectUpdateDisabledTooltip from '../../ProjectUpdateDisabledTooltip' +import { CANCELLATION_REASONS } from '../../Billing.constants' export interface ExitSurveyModalProps { visible: boolean diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx index 8f93a5cb0ae..cf41737acbc 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx @@ -39,12 +39,12 @@ const SubscriptionTier = ({}: SubscriptionTierProps) => {

Subscription plan

- To manage your billing address, emails or tax IDs, head to your{' '} + To manage your billing address, emails or Tax ID, head to your{' '} - -

+ + organization settings -

+ .
diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/Tier.constants.ts b/studio/components/interfaces/BillingV2/Subscription/Tier/Tier.constants.ts deleted file mode 100644 index 20ad87687bc..00000000000 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/Tier.constants.ts +++ /dev/null @@ -1,94 +0,0 @@ -export interface PricingInformation { - id: string - new: boolean - name: string - preface?: string - features: string[] - footer?: string -} - -// This only contains the meta information of plans like description and features, prices are from the API -// Also ideally shift this to common folder (e.g packages/data) -export const SUBSCRIPTION_PLANS: PricingInformation[] = [ - { - id: 'tier_free', - new: false, - name: 'Free', - preface: undefined, - features: [ - 'Social OAuth providers', - 'Up to 500MB database & 1GB file storage', - 'Up to 2GB bandwidth', - 'Up to 50MB file uploads', - '50,000 monthly active users', - 'Up to 500K Edge Function invocations', - '200 concurrent Realtime connections', - '2 million Realtime messages', - '1-day log retention', - 'Community support', - ], - footer: undefined, - }, - { - id: 'tier_pro', - new: false, - name: 'Pro', - preface: undefined, - features: [ - 'No project pausing', - '8GB database & 100GB file storage', - '50GB bandwidth', - '5GB file uploads', - '100,000 monthly active users', - '2M Edge Function invocations', - '500 concurrent Realtime connections', - '5 million Realtime messages', - '7-day log retention', - 'Email support', - 'Daily backups', - ], - footer: - 'Your cost control settings determine if you wish to pay for anything more than the above.', - }, - { - id: 'tier_team', - new: true, - name: 'Team', - preface: 'Everything in Pro, plus:', - features: [ - 'Organization member roles (ABAC)', - 'Standardised Security Questionnaire', - 'SOC2', - 'SSO for Supabase Dashboard', - 'Priority email support & SLAs', - '14 day backups', - '28 day log retention', - ], - footer: undefined, - }, - { - id: 'tier_enterprise', - new: false, - name: 'Enterprise', - preface: 'For large-scale applications managing serious workloads', - features: [`Designated Support manager & SLAs`, `SSO/ SAML`, `Custom contracts & invoicing`], - footer: undefined, - }, -] - -export const CANCELLATION_REASONS = [ - 'Pricing', - "My project isn't getting traction", - 'Poor customer service', - 'Missing feature', - "I didn't see the value", - "Supabase didn't meet my needs", - 'Dashboard is too complicated', - 'Postgres is too complicated', - 'Problem not solved', - 'Bug issues', - 'I decided to use something else', - 'My work has finished/discontinued', - 'I’m migrating to/starting a new project', - 'None of the above', -] diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx index bbedfcdd711..f9e81a85be2 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx @@ -5,9 +5,7 @@ import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-l import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import { useProjectPlansQuery } from 'data/subscriptions/project-plans-query' import { useProjectSubscriptionUpdateMutation } from 'data/subscriptions/project-subscription-update-mutation' -import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query' -import { useFlag, useStore } from 'hooks' -import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants' +import { useStore } from 'hooks' import Link from 'next/link' import { useEffect, useState } from 'react' import { useSubscriptionPageStateSnapshot } from 'state/subscription-page' @@ -16,7 +14,9 @@ import EnterpriseCard from './EnterpriseCard' import ExitSurveyModal from './ExitSurveyModal' import MembersExceedLimitModal from './MembersExceedLimitModal' import PaymentMethodSelection from './PaymentMethodSelection' -import { SUBSCRIPTION_PLANS } from './Tier.constants' +import { plans as subscriptionsPlans } from 'shared-data/plans' +import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query' +import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants' const TierUpdateSidePanel = () => { const { ui } = useStore() @@ -34,18 +34,16 @@ const TierUpdateSidePanel = () => { const onClose = () => snap.setPanelKey(undefined) const { data: plans, isLoading: isLoadingPlans } = useProjectPlansQuery({ projectRef }) + const { data: subscription } = useProjectSubscriptionV2Query({ projectRef }) const { data: addons } = useProjectAddonsQuery({ projectRef }) const { data: membersExceededLimit } = useFreeProjectLimitCheckQuery({ slug }) - const { data: subscription, isLoading } = useProjectSubscriptionV2Query({ projectRef }) const { mutateAsync: updateSubscriptionTier } = useProjectSubscriptionUpdateMutation() const availablePlans = plans ?? [] const subscriptionAddons = addons?.selected_addons ?? [] - const userIsOnTeamTier = subscription?.plan?.id === 'team' - const teamTierEnabled = useFlag('teamTier') || userIsOnTeamTier const hasMembersExceedingFreeTierLimit = (membersExceededLimit || []).length > 0 - const selectedTierMeta = SUBSCRIPTION_PLANS.find((tier) => tier.id === selectedTier) + const selectedTierMeta = subscriptionsPlans.find((tier) => tier.id === selectedTier) const selectedPlanMeta = availablePlans.find( (plan) => plan.id === selectedTier?.split('tier_')[1] ) @@ -118,22 +116,15 @@ const TierUpdateSidePanel = () => { >
- {SUBSCRIPTION_PLANS.map((plan) => { + {subscriptionsPlans.map((plan) => { const planMeta = availablePlans.find((p) => p.id === plan.id.split('tier_')[1]) + const tierMeta = subscriptionsPlans.find((it) => it.id === plan.id) const price = planMeta?.price ?? 0 const isDowngradeOption = planMeta?.change_type === 'downgrade' const isCurrentPlan = planMeta?.is_current ?? false - if (plan.id === 'tier_team' && !teamTierEnabled) return null if (plan.id === 'tier_enterprise') { - return ( - - ) + return } return ( @@ -141,7 +132,7 @@ const TierUpdateSidePanel = () => { key={plan.id} className={clsx( 'border rounded-md px-4 py-4 flex flex-col items-start justify-between', - teamTierEnabled && plan.id === 'tier_enterprise' ? 'col-span-12' : 'col-span-4', + plan.id === 'tier_enterprise' ? 'col-span-12' : 'col-span-12 md:col-span-4', plan.id === 'tier_enterprise' ? 'bg-scale-200' : 'bg-scale-300' )} > @@ -152,9 +143,9 @@ const TierUpdateSidePanel = () => {
Current plan
- ) : plan.new ? ( + ) : plan.nameBadge ? (
- New + {plan.nameBadge}
) : ( <> @@ -169,32 +160,38 @@ const TierUpdateSidePanel = () => { ) : (

${price}

)} -

per month

+

{tierMeta?.costUnit}

-
-
- Usage based plan +
+
+ {tierMeta?.warning}
{isCurrentPlan ? ( - ) : ( + ) : plan.id !== PRICING_TIER_PRODUCT_IDS.TEAM ? ( + ) : ( + + + + + )}
diff --git a/studio/components/interfaces/BillingV2/Usage/Activity.tsx b/studio/components/interfaces/BillingV2/Usage/Activity.tsx index b6bb88ef7c1..29fff89ff43 100644 --- a/studio/components/interfaces/BillingV2/Usage/Activity.tsx +++ b/studio/components/interfaces/BillingV2/Usage/Activity.tsx @@ -8,9 +8,16 @@ export interface ActivityProps { startDate: string | undefined endDate: string | undefined subscription: ProjectSubscriptionResponse | undefined + currentBillingCycleSelected: boolean } -const Activity = ({ projectRef, subscription, startDate, endDate }: ActivityProps) => { +const Activity = ({ + projectRef, + subscription, + startDate, + endDate, + currentBillingCycleSelected, +}: ActivityProps) => { const { data: mauData, isLoading: isLoadingMauData } = useDailyStatsQuery({ projectRef, attribute: 'total_auth_billing_period_mau', @@ -108,9 +115,10 @@ const Activity = ({ projectRef, subscription, startDate, endDate }: ActivityProp return ( ) } diff --git a/studio/components/interfaces/BillingV2/Usage/Bandwidth.tsx b/studio/components/interfaces/BillingV2/Usage/Bandwidth.tsx index c013dc314b0..55391989118 100644 --- a/studio/components/interfaces/BillingV2/Usage/Bandwidth.tsx +++ b/studio/components/interfaces/BillingV2/Usage/Bandwidth.tsx @@ -8,9 +8,16 @@ export interface BandwidthProps { startDate: string | undefined endDate: string | undefined subscription: ProjectSubscriptionResponse | undefined + currentBillingCycleSelected: boolean } -const Bandwidth = ({ projectRef, subscription, startDate, endDate }: BandwidthProps) => { +const Bandwidth = ({ + projectRef, + subscription, + startDate, + endDate, + currentBillingCycleSelected, +}: BandwidthProps) => { const { data: dbEgressData, isLoading: isLoadingDbEgressData } = useDailyStatsQuery({ projectRef, attribute: 'total_egress_modified', @@ -47,9 +54,10 @@ const Bandwidth = ({ projectRef, subscription, startDate, endDate }: BandwidthPr return ( ) } diff --git a/studio/components/interfaces/BillingV2/Usage/Infrastructure.tsx b/studio/components/interfaces/BillingV2/Usage/Infrastructure.tsx index 9be2b2ffb20..5b3b4e1d203 100644 --- a/studio/components/interfaces/BillingV2/Usage/Infrastructure.tsx +++ b/studio/components/interfaces/BillingV2/Usage/Infrastructure.tsx @@ -3,7 +3,7 @@ import { DataPoint } from 'data/analytics/constants' import { useInfraMonitoringQuery } from 'data/analytics/infra-monitoring-query' import dayjs from 'dayjs' import Link from 'next/link' -import { Alert, Button } from 'ui' +import { Alert, Button, IconBarChart2 } from 'ui' import SectionContent from './SectionContent' import SectionHeader from './SectionHeader' import { COMPUTE_INSTANCE_SPECS, USAGE_CATEGORIES } from './Usage.constants' @@ -11,35 +11,27 @@ import { getUpgradeUrlFromV2Subscription } from './Usage.utils' import UsageBarChart from './UsageBarChart' import Panel from 'components/ui/Panel' import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query' -import { useMemo } from 'react' +import { useFlag } from 'hooks' export interface InfrastructureProps { projectRef: string + startDate?: string + endDate?: string + currentBillingCycleSelected: boolean } -// [Joshen] Need to update the IO budget chart to show burst mbps and duration next time - -const Infrastructure = ({ projectRef }: InfrastructureProps) => { +const Infrastructure = ({ + projectRef, + startDate, + endDate, + currentBillingCycleSelected, +}: InfrastructureProps) => { + const enableSubscriptionV2 = useFlag('subscriptionV2') const { data: subscription } = useProjectSubscriptionV2Query({ projectRef }) - const { current_period_start, current_period_end } = subscription ?? {} - const startDate = useMemo(() => { - return current_period_start ? new Date(current_period_start * 1000).toISOString() : undefined - }, [current_period_start]) - - const endDate = useMemo(() => { - const periodEndDate = current_period_end ? new Date(current_period_end * 1000) : undefined - // If end date is in future, set end date to now - if (periodEndDate && dayjs(periodEndDate).isAfter(dayjs())) { - // LF seems to have an issue with the milliseconds, causes infinite loading sometimes - return new Date().toISOString().slice(0, -5) + 'Z' - } else if (periodEndDate) { - return periodEndDate.toISOString() - } - }, [current_period_end]) const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === 'infra') - const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription) + const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription, enableSubscriptionV2) const isFreeTier = subscription?.plan?.id === 'free' const currentComputeInstance = subscription?.addons.find((addon) => addon.supabase_prod_id.includes('_instance_') @@ -55,7 +47,7 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => { if (diffInHours <= 48) { interval = '1h' - dateFormat = 'HH a' + dateFormat = 'h a' } } @@ -119,7 +111,7 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => { {attribute.key === 'disk_io_consumption' && ( <> - {highestIoBudgetConsumption >= 100 ? ( + {currentBillingCycleSelected && highestIoBudgetConsumption >= 100 ? (

Your workload has used up all the burst IO throughput minutes and ran at the @@ -134,7 +126,7 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => { - ) : highestIoBudgetConsumption >= 80 ? ( + ) : currentBillingCycleSelected && highestIoBudgetConsumption >= 80 ? (

Your workload is about to use up all the burst IO throughput minutes during @@ -154,10 +146,6 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => {

Disk IO Bandwidth

-

- The disk performance of your workload is determined by the Disk IO bandwidth. -

- {currentComputeInstanceSpecs.maxBandwidth === currentComputeInstanceSpecs.baseBandwidth ? (

@@ -191,17 +179,20 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => { {currentComputeInstanceSpecs.baseBandwidth.toLocaleString()} Mbps

-
-

Daily burst time limit

-

30 mins

-
+ {currentComputeInstanceSpecs.maxBandwidth !== + currentComputeInstanceSpecs.baseBandwidth && ( +
+

Daily burst time limit

+

30 mins

+
+ )}
)}
{attribute.key === 'disk_io_consumption' ? ( -

IO consumed per {interval === '1d' ? 'day' : 'hour'}

+

Disk IO consumed per {interval === '1d' ? 'day' : 'hour'}

) : (

Max{' '} @@ -250,8 +241,9 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => {

-

No data

-

There is no data in period

+ +

No data in period

+

May take a few minutes to show

diff --git a/studio/components/interfaces/BillingV2/Usage/SizeAndCounts.tsx b/studio/components/interfaces/BillingV2/Usage/SizeAndCounts.tsx index 2f66c88e095..6527a636ee7 100644 --- a/studio/components/interfaces/BillingV2/Usage/SizeAndCounts.tsx +++ b/studio/components/interfaces/BillingV2/Usage/SizeAndCounts.tsx @@ -8,9 +8,16 @@ export interface SizeAndCountsProps { startDate: string | undefined endDate: string | undefined subscription: ProjectSubscriptionResponse | undefined + currentBillingCycleSelected: boolean } -const SizeAndCounts = ({ projectRef, startDate, endDate, subscription }: SizeAndCountsProps) => { +const SizeAndCounts = ({ + projectRef, + startDate, + endDate, + subscription, + currentBillingCycleSelected, +}: SizeAndCountsProps) => { const { data: dbSizeData, isLoading: isLoadingDbSizeData } = useDailyStatsQuery({ projectRef, attribute: 'total_db_size_bytes', @@ -61,9 +68,10 @@ const SizeAndCounts = ({ projectRef, startDate, endDate, subscription }: SizeAnd return ( ) } diff --git a/studio/components/interfaces/BillingV2/Usage/Usage.constants.tsx b/studio/components/interfaces/BillingV2/Usage/Usage.constants.tsx index c5433c5abbe..30ae0d4cc3c 100644 --- a/studio/components/interfaces/BillingV2/Usage/Usage.constants.tsx +++ b/studio/components/interfaces/BillingV2/Usage/Usage.constants.tsx @@ -80,7 +80,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'disk_io', key: 'disk_io_consumption', attribute: 'disk_io_consumption', - name: 'Disk IO bandwidth', + name: 'Disk IO Bandwidth', unit: 'percentage', links: [ { @@ -89,7 +89,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ }, ], description: - 'Smaller compute instances (below 4XL) can burst up to their largest throughput and IOPS for 30 minutes in a day. Beyond that, the performance reverts to the baseline. Your disk budget gets replenished throughout the day.', + 'The disk performance of your workload is determined by the Disk IO bandwidth.\nSmaller compute instances (below 4XL) can burst up to their largest throughput and IOPS for 30 minutes in a day. Beyond that, the performance reverts to the baseline. Your disk budget gets replenished throughout the day.', chartDescription: '', }, ], @@ -103,7 +103,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'dbEgress', key: 'db_egress', attribute: 'total_egress_modified', - name: 'Database egress', + name: 'Database Egress', unit: 'bytes', description: 'Contains any outgoing traffic (egress) from your database.\nBilling is based on the total sum of egress in GB throughout your billing period.', @@ -113,7 +113,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'storageEgress', key: 'storage_egress', attribute: 'total_storage_egress', - name: 'Storage egress', + name: 'Storage Egress', unit: 'bytes', description: 'All requests to view and download your storage items go through our CDN. We sum up all outgoing traffic (egress) for storage related requests through our CDN. We do not differentiate between cache and no cache hits.\nBilling is based on the total amount of egress in GB throughout your billing period.', @@ -166,7 +166,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'storageSize', key: 'storage_size', attribute: 'total_storage_size_bytes', - name: 'Storage size', + name: 'Storage Size', chartPrefix: 'Max ', unit: 'bytes', description: @@ -177,7 +177,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'funcCount', key: 'func_count', attribute: 'total_func_count', - name: 'Edge function count', + name: 'Edge Function Count', chartPrefix: 'Max ', unit: 'absolute', description: @@ -217,7 +217,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'storageImageTransformations', key: 'storage_image_render_count', attribute: 'total_storage_image_render_count', - name: 'Storage image transformations', + name: 'Storage Image Transformations', unit: 'absolute', description: 'We count all images that were transformed in the billing period, ignoring any transformations.\nUsage example: You transform one image with four different size transformations and another image with just a single transformations. It counts as two, as only two images were transformed.\nBilling is based on the count of (origin) images that used transformations throughout the billing period. Resets every billing cycle.', @@ -228,7 +228,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'functionInvocations', key: 'func_invocations', attribute: 'total_func_invocations', - name: 'Edge function invocations', + name: 'Edge Function Invocations', unit: 'absolute', description: 'Every serverless function invocation independent of response status is counted.\nBilling is based on the sum of all invocations throughout your billing period.', @@ -238,7 +238,7 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'realtimeMessageCount', key: 'realtime_message_count', attribute: 'total_realtime_message_count', - name: 'Realtime message count', + name: 'Realtime Message Count', unit: 'absolute', description: "Count of messages going through Realtime.\nUsage example: If you do a database change and 5 clients listen to that change via Realtime, that's 5 messages. If you broadcast a message and 4 clients listen to that, that's 5 messages (1 message sent, 4 received).\nBilling is based on the total amount of messages throughout your billing period.", @@ -248,11 +248,11 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ anchor: 'realtimePeakConnection', key: 'realtime_peak_connection', attribute: 'total_realtime_peak_connection', - name: 'Realtime peak connections', + name: 'Realtime Peak Connections', chartPrefix: 'Max ', unit: 'absolute', description: - 'Total number of successful connections (not connection attempts).\nBilling is based on the maximum amount of concurrent peak connections throughout your billing period.', + 'Total number of successful connections. Connections attempts are not counted towards usage.\nBilling is based on the maximum amount of concurrent peak connections throughout your billing period.', chartDescription: 'The data refreshes every 24 hours.', }, ], diff --git a/studio/components/interfaces/BillingV2/Usage/Usage.tsx b/studio/components/interfaces/BillingV2/Usage/Usage.tsx index 6e4989e4c41..698718dcd2f 100644 --- a/studio/components/interfaces/BillingV2/Usage/Usage.tsx +++ b/studio/components/interfaces/BillingV2/Usage/Usage.tsx @@ -4,10 +4,9 @@ import { useInfraMonitoringQuery } from 'data/analytics/infra-monitoring-query' import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query' import { useProjectUsageQuery } from 'data/usage/project-usage-query' import dayjs from 'dayjs' -import Link from 'next/link' import { useMemo, useRef, useState } from 'react' import { InView } from 'react-intersection-observer' -import { Button, IconAlertCircle, IconLoader, Listbox } from 'ui' +import { IconAlertCircle, IconLoader } from 'ui' import { cn } from 'ui/src/utils/cn' import Activity from './Activity' import Bandwidth from './Bandwidth' @@ -15,6 +14,8 @@ import Infrastructure from './Infrastructure' import SizeAndCounts from './SizeAndCounts' import { USAGE_CATEGORIES, USAGE_STATUS } from './Usage.constants' import { getUsageStatus } from './Usage.utils' +import DateRangePicker from 'components/to-be-cleaned/DateRangePicker' +import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from 'lib/constants' export type usageSectionIds = 'infra' | 'bandwidth' | 'sizeCount' | 'activity' @@ -32,36 +33,54 @@ const Usage = () => { const [activeTab, setActiveTab] = useState('infra') + const [dateRange, setDateRange] = useState() + const { data: usage } = useProjectUsageQuery({ projectRef: ref }) const { data: subscription, isLoading: isLoadingSubscription } = useProjectSubscriptionV2Query({ projectRef: selectedProjectRef, }) - const { current_period_start, current_period_end } = subscription ?? {} + const currentBillingCycleSelected = useMemo(() => { + // Selected by default + if (!dateRange?.period_start || !dateRange?.period_end || !subscription) return true + + const { current_period_start, current_period_end } = subscription + + return ( + dayjs(dateRange.period_start.date).isSame(new Date(current_period_start * 1000)) && + dayjs(dateRange.period_end.date).isSame(new Date(current_period_end * 1000)) + ) + }, [dateRange, subscription]) const startDate = useMemo(() => { - return current_period_start ? new Date(current_period_start * 1000).toISOString() : undefined - }, [current_period_start]) - - const endDate = - current_period_end !== undefined ? new Date(current_period_end * 1000).toISOString() : undefined - - const dailyStatsEndDate = useMemo(() => { // If end date is in future, set end date to now - if (endDate && dayjs(endDate).isAfter(dayjs())) { + if (!dateRange?.period_start?.date) { + return undefined + } else { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes - return new Date().toISOString().slice(0, -5) + 'Z' - } else if (endDate) { - return endDate + return new Date(dateRange?.period_start?.date).toISOString().slice(0, -5) + 'Z' } - }, [endDate]) + }, [dateRange, subscription]) + + const endDate = useMemo(() => { + // If end date is in future, set end date to end of current day + if (dateRange?.period_end?.date && dayjs(dateRange.period_end.date).isAfter(dayjs())) { + // LF seems to have an issue with the milliseconds, causes infinite loading sometimes + // In order to have full days from Prometheus metrics when using 1d interval, + // the time needs to be greater or equal than the time of the start date + return dayjs().endOf('day').toISOString().slice(0, -5) + 'Z' + } else if (dateRange?.period_end?.date) { + // LF seems to have an issue with the milliseconds, causes infinite loading sometimes + return new Date(dateRange.period_end.date).toISOString().slice(0, -5) + 'Z' + } + }, [dateRange, subscription]) const { data: ioBudgetData } = useInfraMonitoringQuery({ projectRef: selectedProjectRef, attribute: 'disk_io_budget', interval: '1d', - startDate, - endDate, + startDate: dateRange?.period_start?.date, + endDate: dateRange?.period_end?.date, }) const currentDayIoBudget = Number( ioBudgetData?.data.find((x) => x.periodStartFormatted === dayjs().format('DD MMM'))?.[ @@ -117,7 +136,7 @@ const Usage = () => { return ( <> -
+

Usage

@@ -127,22 +146,19 @@ const Usage = () => {
- {}} - > - - Current billing cycle - - - Previous billing cycle - - + {!isLoadingSubscription && ( + + )} + {isLoadingSubscription ? ( ) : subscription !== undefined ? ( @@ -150,7 +166,7 @@ const Usage = () => {

- Project is on {subscription.plan.name} + Project is on {subscription.plan.name} plan

{billingCycleStart.format('DD MMM YYYY')} -{' '} @@ -159,18 +175,6 @@ const Usage = () => {

) : null}
-
{USAGE_CATEGORIES.map((category) => { @@ -197,9 +201,13 @@ const Usage = () => { : 'opacity-50' )} > - {usageBillingEnabled === false && status === USAGE_STATUS.APPROACHING ? ( + {currentBillingCycleSelected && + usageBillingEnabled === false && + status === USAGE_STATUS.APPROACHING ? ( - ) : usageBillingEnabled === false && status === USAGE_STATUS.EXCEEDED ? ( + ) : currentBillingCycleSelected && + usageBillingEnabled === false && + status === USAGE_STATUS.EXCEEDED ? ( ) : null}

{category.name}

@@ -212,7 +220,12 @@ const Usage = () => { inView && setActiveTab('infra')}>
- +
{ projectRef={selectedProjectRef} subscription={subscription} startDate={startDate} - endDate={dailyStatsEndDate} + endDate={endDate} + currentBillingCycleSelected={currentBillingCycleSelected} />
@@ -239,7 +253,8 @@ const Usage = () => { projectRef={selectedProjectRef} subscription={subscription} startDate={startDate} - endDate={dailyStatsEndDate} + endDate={endDate} + currentBillingCycleSelected={currentBillingCycleSelected} />
@@ -253,7 +268,8 @@ const Usage = () => { projectRef={selectedProjectRef} subscription={subscription} startDate={startDate} - endDate={dailyStatsEndDate} + endDate={endDate} + currentBillingCycleSelected={currentBillingCycleSelected} />
diff --git a/studio/components/interfaces/BillingV2/Usage/Usage.utils.ts b/studio/components/interfaces/BillingV2/Usage/Usage.utils.ts index 11e35b9331d..2d85f0f4177 100644 --- a/studio/components/interfaces/BillingV2/Usage/Usage.utils.ts +++ b/studio/components/interfaces/BillingV2/Usage/Usage.utils.ts @@ -51,17 +51,28 @@ export const getUpgradeUrl = (projectRef: string, subscription?: StripeSubscript export const getUpgradeUrlFromV2Subscription = ( projectRef: string, - subscription?: ProjectSubscriptionResponse + subscription?: ProjectSubscriptionResponse, + newSubscriptionPage?: boolean ) => { - if (!subscription) return `/project/${projectRef}/settings/billing/update` + if (!subscription) { + return !newSubscriptionPage + ? `/project/${projectRef}/settings/billing/update` + : `/project/${projectRef}/settings/billing/subscription` + } - return subscription?.plan.id === 'enterprise' - ? `/project/${projectRef}/settings/billing/update/enterprise` - : subscription?.plan.id === 'team' - ? `/project/${projectRef}/settings/billing/update/team` - : subscription?.plan.id === 'free' - ? `/project/${projectRef}/settings/billing/update` - : `/project/${projectRef}/settings/billing/update/pro` + if (!newSubscriptionPage) { + return subscription?.plan.id === 'enterprise' + ? `/project/${projectRef}/settings/billing/update/enterprise` + : subscription?.plan.id === 'team' + ? `/project/${projectRef}/settings/billing/update/team` + : subscription?.plan.id === 'free' + ? `/project/${projectRef}/settings/billing/update` + : `/project/${projectRef}/settings/billing/update/pro` + } else { + return subscription?.plan?.id === 'pro' && subscription?.usage_billing_enabled === false + ? `/project/${projectRef}/settings/billing/subscription#cost-control` + : `/project/${projectRef}/settings/billing/subscription?panel=subscriptionPlan` + } } const compactNumberFormatter = new Intl.NumberFormat('en-US', { diff --git a/studio/components/interfaces/BillingV2/Usage/UsageBarChart.tsx b/studio/components/interfaces/BillingV2/Usage/UsageBarChart.tsx index 681a8f2b322..226c37589e1 100644 --- a/studio/components/interfaces/BillingV2/Usage/UsageBarChart.tsx +++ b/studio/components/interfaces/BillingV2/Usage/UsageBarChart.tsx @@ -9,7 +9,6 @@ import { XAxis, YAxis, } from 'recharts' -import { Y_DOMAIN_CEILING_MULTIPLIER } from './Usage.constants' import dayjs from 'dayjs' // [Joshen] This BarChart is specifically for usage, hence not a reusable component, and not diff --git a/studio/components/interfaces/BillingV2/Usage/UsageSection.tsx b/studio/components/interfaces/BillingV2/Usage/UsageSection.tsx index 9ef58b96335..d30c3d8d6ad 100644 --- a/studio/components/interfaces/BillingV2/Usage/UsageSection.tsx +++ b/studio/components/interfaces/BillingV2/Usage/UsageSection.tsx @@ -18,6 +18,8 @@ import { ChartYFormatterCompactNumber, getUpgradeUrlFromV2Subscription } from '. import { formatBytes } from 'lib/helpers' import UsageBarChart from './UsageBarChart' import Panel from 'components/ui/Panel' +import * as Tooltip from '@radix-ui/react-tooltip' +import { useFlag } from 'hooks' interface UsageSectionProps { projectRef: string @@ -26,9 +28,17 @@ interface UsageSectionProps { chartMeta: { [key: string]: { data: DataPoint[]; margin: number; isLoading: boolean; hasNoData: boolean } } + currentBillingCycleSelected: boolean } -const UsageSection = ({ projectRef, categoryKey, chartMeta, subscription }: UsageSectionProps) => { +const UsageSection = ({ + projectRef, + categoryKey, + chartMeta, + subscription, + currentBillingCycleSelected, +}: UsageSectionProps) => { + const enableSubscriptionV2 = useFlag('subscriptionV2') const { data: usage } = useProjectUsageQuery({ projectRef }) const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === categoryKey) @@ -37,7 +47,7 @@ const UsageSection = ({ projectRef, categoryKey, chartMeta, subscription }: Usag const usageBasedBilling = subscription?.usage_billing_enabled const exceededLimitStyle = !usageBasedBilling ? 'text-red-900' : 'text-amber-900' - const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription) + const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription, enableSubscriptionV2) return ( <> @@ -62,34 +72,73 @@ const UsageSection = ({ projectRef, categoryKey, chartMeta, subscription }: Usag

{attribute.name} usage

- {!usageBasedBilling && usageRatio >= 1 ? ( -
- -

Exceeded limit

-
- ) : !usageBasedBilling && usageRatio >= USAGE_APPROACHING_THRESHOLD ? ( -
- -

Approaching limit

-
- ) : null} + {currentBillingCycleSelected && + usageBasedBilling === false && + usageRatio >= USAGE_APPROACHING_THRESHOLD && ( + + + {!usageBasedBilling && usageRatio >= 1 ? ( +
+ +

Exceeded limit

+
+ ) : ( + !usageBasedBilling && + usageRatio >= USAGE_APPROACHING_THRESHOLD && ( +
+ +

Approaching limit

+
+ ) + )} +
+ + + +
+

+ Exceeding your plans included usage will lead to restrictions to + your project. +

+

+ Upgrade to a usage-based plan or disable the spend cap to avoid + restrictions. +

+
+
+
+
+ )}
- {!usageBasedBilling && usageRatio >= USAGE_APPROACHING_THRESHOLD && ( - - - - - - )} + {currentBillingCycleSelected && + !usageBasedBilling && + usageRatio >= USAGE_APPROACHING_THRESHOLD && ( + + + + + + )}
- {usageMeta?.limit > 0 && ( + {currentBillingCycleSelected && usageMeta?.limit > 0 && ( = USAGE_APPROACHING_THRESHOLD + : usageBasedBilling === false && usageRatio >= USAGE_APPROACHING_THRESHOLD ? 'bg-amber-900' : 'bg-scale-1100' )} @@ -127,7 +176,7 @@ const UsageSection = ({ projectRef, categoryKey, chartMeta, subscription }: Usag : (usageMeta?.usage ?? 0).toLocaleString()}

- {usageMeta?.limit > 0 && ( + {currentBillingCycleSelected && usageMeta?.limit > 0 && (

Overage in period

@@ -163,7 +212,7 @@ const UsageSection = ({ projectRef, categoryKey, chartMeta, subscription }: Usag

- ) : chartData.length > 1 && notAllValuesZero ? ( + ) : chartData.length > 0 && notAllValuesZero ? (
-

No data in period

-

- May take up to 24 hours to show -

+

No data in period

+

May take up to 24 hours to show

diff --git a/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectButton.tsx b/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectButton.tsx index 7a80c2d4b9f..b1fe6d9553f 100644 --- a/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectButton.tsx +++ b/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectButton.tsx @@ -8,7 +8,7 @@ import { useStore, checkPermissions } from 'hooks' import { API_URL, PRICING_TIER_PRODUCT_IDS } from 'lib/constants' import { delete_, post } from 'lib/common/fetch' import TextConfirmModal from 'components/ui/Modals/TextConfirmModal' -import { CANCELLATION_REASONS } from 'components/interfaces/Billing/Billing.constants' +import { CANCELLATION_REASONS } from 'components/interfaces/BillingV2/Billing.constants' interface Props { type?: 'danger' | 'default' diff --git a/studio/components/interfaces/Settings/Logs/UpgradePrompt.tsx b/studio/components/interfaces/Settings/Logs/UpgradePrompt.tsx index 59fde57debf..25a45b84b75 100644 --- a/studio/components/interfaces/Settings/Logs/UpgradePrompt.tsx +++ b/studio/components/interfaces/Settings/Logs/UpgradePrompt.tsx @@ -17,10 +17,6 @@ const UpgradePrompt: React.FC = ({ show, setShowUpgradePrompt, subscripti const router = useRouter() const { ref } = router.query - // Team plan is enabled when the flag is turned on OR the user is already on the team plan (manually assigned by us) - const userIsOnTeamTier = subscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM - const teamTierEnabled = useFlag('teamTier') || userIsOnTeamTier - return ( = ({ show, setShowUpgradePrompt, subscripti

Pro

{TIER_QUERY_LIMITS.PRO.text}

- {teamTierEnabled && ( -
-

Team

-

{TIER_QUERY_LIMITS.TEAM.text}

-
- )} +
+

Team

+

{TIER_QUERY_LIMITS.TEAM.text}

+

Enterprise

{TIER_QUERY_LIMITS.ENTERPRISE.text}

diff --git a/studio/components/interfaces/Settings/Vault/Keys/EncryptionKeysManagement.tsx b/studio/components/interfaces/Settings/Vault/Keys/EncryptionKeysManagement.tsx index 3bc291cc295..01e4a6d527f 100644 --- a/studio/components/interfaces/Settings/Vault/Keys/EncryptionKeysManagement.tsx +++ b/studio/components/interfaces/Settings/Vault/Keys/EncryptionKeysManagement.tsx @@ -141,7 +141,7 @@ const EncryptionKeysManagement: FC = ({}) => {
- +
diff --git a/studio/pages/project/[ref]/settings/billing/update/index.tsx b/studio/pages/project/[ref]/settings/billing/update/index.tsx index 024c2d06407..b1da19e8d66 100644 --- a/studio/pages/project/[ref]/settings/billing/update/index.tsx +++ b/studio/pages/project/[ref]/settings/billing/update/index.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/router' import { observer } from 'mobx-react-lite' import { Button, Modal } from 'ui' -import { useFlag, useStore } from 'hooks' +import { useStore } from 'hooks' import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query' import { get } from 'lib/common/fetch' import { API_URL, PRICING_TIER_PRODUCT_IDS, STRIPE_PRODUCT_IDS } from 'lib/constants' @@ -103,10 +103,6 @@ const BillingUpdate: NextPageWithLayout = () => { } } - // Team tier is enabled when the flag is turned on OR the user is already on the team tier (manually assigned by us) - const userIsOnTeamTier = subscription?.tier?.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.TEAM - const teamTierEnabled = useFlag('teamTier') || userIsOnTeamTier - if (isLoadingProducts || isEnterprise) { return (
@@ -115,13 +111,11 @@ const BillingUpdate: NextPageWithLayout = () => { ) } - const productTiers = (products?.tiers ?? []).filter( - (tier) => teamTierEnabled || tier.id !== STRIPE_PRODUCT_IDS.TEAM - ) + const productTiers = (products?.tiers ?? []) return ( <> -
+
{ + acc[curr.table_id] ??= [] + acc[curr.table_id].push(curr) + return acc + }, {} as Record) + const foreignTables: PostgresTable[] = [] + foreignTablesResponse.forEach((foreignTable: PostgresTable) => { + const columns = columnsByTableId[foreignTable.id] + foreignTables.push({ ...foreignTable, columns }) + }) + + this.setDataArray(foreignTables) + return foreignTables as any + } + // loadBySchema is not supported in this store async loadBySchema(schema: string) { return [] diff --git a/studio/stores/pgmeta/MaterializedViewStore.ts b/studio/stores/pgmeta/MaterializedViewStore.ts index 96d81b3ceb4..71a98dc43df 100644 --- a/studio/stores/pgmeta/MaterializedViewStore.ts +++ b/studio/stores/pgmeta/MaterializedViewStore.ts @@ -1,4 +1,4 @@ -import { PostgresMaterializedView } from '@supabase/postgres-meta' +import { PostgresColumn, PostgresMaterializedView } from '@supabase/postgres-meta' import { ResponseError } from 'types' import PostgresMetaInterface, { IPostgresMetaInterface } from '../common/PostgresMetaInterface' import { IRootStore } from '../RootStore' @@ -22,6 +22,39 @@ export default class MaterializedViewStore extends PostgresMetaInterface { + acc[curr.table_id] ??= [] + acc[curr.table_id].push(curr) + return acc + }, {} as Record) + const materializedViews: PostgresMaterializedView[] = [] + materializedViewsResponse.forEach((materializedView: PostgresMaterializedView) => { + const columns = columnsByTableId[materializedView.id] + materializedViews.push({ ...materializedView, columns }) + }) + + this.setDataArray(materializedViews) + return materializedViews as any + } + async loadById(id: number | string) { try { const url = `${this.url}?id=${id}` diff --git a/studio/stores/pgmeta/TableStore.ts b/studio/stores/pgmeta/TableStore.ts index 5063db74c65..f6da9e1807d 100644 --- a/studio/stores/pgmeta/TableStore.ts +++ b/studio/stores/pgmeta/TableStore.ts @@ -1,5 +1,5 @@ import { action, makeObservable } from 'mobx' -import type { PostgresTable } from '@supabase/postgres-meta' +import type { PostgresColumn, PostgresTable } from '@supabase/postgres-meta' import PostgresMetaInterface, { IPostgresMetaInterface } from '../common/PostgresMetaInterface' import { IRootStore } from '../RootStore' @@ -25,6 +25,39 @@ export default class TableStore extends PostgresMetaInterface { }) } + // Customize TableStore fetchData method to improve request performance + async fetchData() { + const headers = { 'Content-Type': 'application/json', ...this.headers } + // load all tables w/o columns info + const urlTables = this.url.includes('?') + ? `${this.url}&include_columns=false` + : `${this.url}?include_columns=false` + // load all columns + const urlColumns = this.url.replace('/tables', '/columns') + const [tablesResponse, columnsResponse] = await Promise.all([ + get(urlTables, { headers }), + get(urlColumns, { headers }), + ]) + if (tablesResponse.error) throw tablesResponse.error + if (columnsResponse.error) throw columnsResponse.error + + // merge 2 response to create the final array + const columnsByTableId = (columnsResponse as PostgresColumn[]) + .reduce((acc, curr) => { + acc[curr.table_id] ??= [] + acc[curr.table_id].push(curr) + return acc + }, {} as Record) + const tables: PostgresTable[] = [] + tablesResponse.forEach((table: PostgresTable) => { + const columns = columnsByTableId[table.id] + tables.push({ ...table, columns }) + }) + + this.setDataArray(tables) + return tables as any + } + async loadById(id: number | string) { try { const url = this.url.includes('?') ? `${this.url}&id=${id}` : `${this.url}?id=${id}` diff --git a/studio/stores/pgmeta/ViewStore.ts b/studio/stores/pgmeta/ViewStore.ts index 56067240562..063530b2390 100644 --- a/studio/stores/pgmeta/ViewStore.ts +++ b/studio/stores/pgmeta/ViewStore.ts @@ -2,6 +2,7 @@ import { ResponseError, SchemaView } from 'types' import PostgresMetaInterface, { IPostgresMetaInterface } from '../common/PostgresMetaInterface' import { IRootStore } from '../RootStore' import { get } from 'lib/common/fetch' +import { PostgresColumn, PostgresView } from '@supabase/postgres-meta' export interface IViewStore extends IPostgresMetaInterface { loadById: (id: number | string) => Promise | { error: ResponseError }> @@ -19,6 +20,39 @@ export default class ViewStore extends PostgresMetaInterface { super(rootStore, dataUrl, headers, options) } + // Customize ViewStore fetchData method to improve request performance + async fetchData() { + const headers = { 'Content-Type': 'application/json', ...this.headers } + // load all views w/o columns info + const _url = new URL(this.url) + _url.searchParams.set('include_columns', 'false') + const url = `${_url}` + // load all columns + const urlColumns = this.url.replace('/views', '/columns') + const [viewsResponse, columnsResponse] = await Promise.all([ + get(url, { headers }), + get(urlColumns, { headers }), + ]) + if (viewsResponse.error) throw viewsResponse.error + if (columnsResponse.error) throw columnsResponse.error + + // merge 2 response to create the final array + const columnsByTableId = (columnsResponse as PostgresColumn[]) + .reduce((acc, curr) => { + acc[curr.table_id] ??= [] + acc[curr.table_id].push(curr) + return acc + }, {} as Record) + const views: PostgresView[] = [] + viewsResponse.forEach((view: PostgresView) => { + const columns = columnsByTableId[view.id] + views.push({ ...view, columns }) + }) + + this.setDataArray(views as any) + return views as any + } + async loadById(id: number | string) { try { const url = `${this.url}?id=${id}` diff --git a/studio/tests/components/Editor/RowEditor.utils.test.js b/studio/tests/components/Editor/RowEditor.utils.test.js new file mode 100644 index 00000000000..d63806788d8 --- /dev/null +++ b/studio/tests/components/Editor/RowEditor.utils.test.js @@ -0,0 +1,94 @@ +import { parseValue } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils' + +describe('parseValue', () => { + it('should return null when originalValue is null', () => { + const originalValue = null + const format = 'some format' + expect(parseValue(originalValue, format)).toBeNull() + }) + + it('should return originalValue when it is an empty array', () => { + const originalValue = [] + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) + + it('should return originalValue when it is an empty object', () => { + const originalValue = {} + const format = 'some format' + const expectedValue = JSON.stringify(originalValue) + expect(parseValue(originalValue, format)).toEqual(expectedValue) + }) + + it('should return originalValue when it is 0', () => { + const originalValue = 0 + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) + + it('should return originalValue when it is an empty string', () => { + const originalValue = '' + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) + + it('should return originalValue when it is a number and format is not provided', () => { + const originalValue = 42 + const format = '' + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) + + it('should return JSON string representation when originalValue is an object', () => { + const originalValue = { key: 'value' } + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(JSON.stringify(originalValue)) + }) + + it('should handle complex nested object with titles correctly', () => { + const originalValue = { + glossary: { + title: 'parent title', + subItem: { + title: 'subItem title', + items: ['item1', 'item2'], + }, + }, + } + const format = 'some format' + const expectedValue = JSON.stringify(originalValue) + expect(parseValue(originalValue, format)).toEqual(expectedValue) + }) + + it('should handle object with all values set to 0 correctly', () => { + const originalValue = { + width: 0, + height: 0, + length: 0, + weight: 0, + } + const format = 'some format' + const expectedValue = JSON.stringify(originalValue) + expect(parseValue(originalValue, format)).toEqual(expectedValue) + }) + it('should return string representation of originalValue when it is a boolean', () => { + const originalValue = true + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(originalValue.toString()) + }) + + it('should return originalValue for other cases', () => { + const originalValue = 'some value' + const format = 'some format' + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) + + it('should return originalValue even when an error occurs', () => { + const originalValue = 'some value' + const format = 'some format' + // Mocking an error occurring during parsing + JSON.stringify = jest.fn(() => { + throw new Error('Mocked error') + }) + expect(parseValue(originalValue, format)).toEqual(originalValue) + }) +})