mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
129 files changed
+3489
-1822
No files matched your search
@@ -942,6 +942,10 @@ export const ai: NavMenuConstant = {
|
||||
name: 'Google Colab',
|
||||
url: '/guides/ai/google-colab',
|
||||
},
|
||||
{
|
||||
name: 'LlamaIndex',
|
||||
url: '/guides/ai/integrations/llamaindex',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,7 @@ const nextConfig = {
|
||||
|
||||
const configExport = () => {
|
||||
const plugins = [
|
||||
withTM(['ui', 'common', '@supabase/auth-helpers-nextjs']),
|
||||
withTM(['ui', 'common', '@supabase/auth-helpers-nextjs', 'shared-data']),
|
||||
withMDX,
|
||||
withYaml,
|
||||
withBundleAnalyzer,
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -88,19 +88,24 @@ export const integrations = [
|
||||
name: 'OpenAI',
|
||||
description:
|
||||
'OpenAI is an AI research and deployment company. Supabase provides a simple way to use OpenAI in your applications.',
|
||||
href: '/docs/guides/ai/examples/building-chatgpt-plugins',
|
||||
href: '/guides/ai/examples/building-chatgpt-plugins',
|
||||
},
|
||||
{
|
||||
name: 'Hugging Face',
|
||||
description:
|
||||
"Hugging Face is an open-source provider of NLP technologies. Supabase provides a simple way to use Hugging Face's models in your applications.",
|
||||
href: '/docs/guides/ai/hugging-face',
|
||||
href: '/guides/ai/hugging-face',
|
||||
},
|
||||
{
|
||||
name: 'LangChain',
|
||||
description:
|
||||
'LangChain is a language-agnostic, open-source, and self-hosted API for text translation, summarization, and sentiment analysis.',
|
||||
href: '/docs/guides/ai/langchain',
|
||||
href: '/guides/ai/langchain',
|
||||
},
|
||||
{
|
||||
name: 'LlamaIndex',
|
||||
description: 'LlamaIndex is a data framework for your LLM applications.',
|
||||
href: '/guides/ai/integrations/llamaindex',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -119,6 +124,12 @@ export const integrations = [
|
||||
</div>
|
||||
|
||||
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:
|
||||
|
||||
@@ -284,7 +284,7 @@ With our database set up, we need to process and store all `.mdx` files in the `
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```txt
|
||||
```bash
|
||||
NEXT_PUBLIC_SUPABASE_URL=
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
||||
SUPABASE_SERVICE_ROLE_KEY=
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'ai-integration-llamaindex',
|
||||
title:
|
||||
'Learn how to integrate Supabase with LlamaIndex, a data framework for your LLM applications.',
|
||||
subtitle:
|
||||
'Learn how to integrate Supabase with LlamaIndex, a data framework for your LLM applications.',
|
||||
breadcrumb: 'AI Integrations',
|
||||
}
|
||||
|
||||
This guide will walk you through a basic example using the LlamaIndex [SupabaseVectorStore](https://github.com/supabase/supabase/blob/master/examples/ai/llamaindex/llamaindex.ipynb).
|
||||
|
||||
<DatabaseSetup />
|
||||
|
||||
## Launching a notebook
|
||||
|
||||
Launch our [LlamaIndex](https://github.com/supabase/supabase/blob/master/examples/ai/llamaindex/llamaindex.ipynb) notebook in Colab:
|
||||
|
||||
<a
|
||||
className="w-64"
|
||||
href="https://colab.research.google.com/github/supabase/supabase/blob/master/examples/ai/llamaindex/llamaindex.ipynb"
|
||||
>
|
||||
<img src="/docs/img/ai/colab-badge.svg" />
|
||||
</a>
|
||||
|
||||
At the top of the notebook, you'll see a button `Copy to Drive`. Click this button to copy the notebook to your Google Drive.
|
||||
|
||||
## Fill in your OpenAI credentials
|
||||
|
||||
Inside the Notebook, add your `OPENAI_API_KEY` key. Find the cell which contains this code:
|
||||
|
||||
```py
|
||||
import os
|
||||
os.environ['OPENAI_API_KEY'] = "[your_openai_api_key]"
|
||||
```
|
||||
|
||||
## Connecting to your database
|
||||
|
||||
Inside the Notebook, find the cell which specifies the `DB_CONNECTION`. It will contain some code like this:
|
||||
|
||||
```python
|
||||
DB_CONNECTION = "postgresql://<user>:<password>@<host>:<port>/<db_name>"
|
||||
|
||||
# create vector store client
|
||||
vx = vecs.create_client(DB_CONNECTION)
|
||||
```
|
||||
|
||||
Replace the `DB_CONNECTION` with your own connection string for your database, which you set up in first step of this guide.
|
||||
|
||||
## Stepping through the notebook
|
||||
|
||||
Now all that's left is to step through the notebook. You can do this by clicking the "execute" button (`ctrl+enter`) at the top left of each code cell. The notebook guides you through the process of creating a collection, adding data to it, and querying it.
|
||||
|
||||
You can view the inserted items in the [Table Editor](https://app.supabase.com/project/_/editor/), by selecting the `vecs` schema from the schema dropdown.
|
||||
|
||||

|
||||
|
||||
## Resources
|
||||
|
||||
- Visit the LlamaIndex + SupabaseVectorStore [docs](https://gpt-index.readthedocs.io/en/latest/examples/vector_stores/SupabaseVectorIndexDemo.html)
|
||||
- Visit the official LlamaIndex [repo](https://github.com/jerryjliu/llama_index/)
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -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'
|
||||
|
||||
@@ -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.
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/MVYhyGZGLuo"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
> 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
|
||||
@@ -116,7 +125,7 @@ The `Code Exchange` route is required for the [server-side auth flow](https://su
|
||||
|
||||
Create a new file at `app/auth/callback/route.js` and populate with the following:
|
||||
|
||||
```jsx app/auth/callback.route.js
|
||||
```jsx app/auth/callback/route.js
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server'
|
||||
@@ -141,7 +150,7 @@ export async function GET(request) {
|
||||
|
||||
Create a new file at `app/auth/callback/route.ts` and populate with the following:
|
||||
|
||||
```tsx app/auth/callback.route.ts
|
||||
```tsx app/auth/callback/route.ts
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server'
|
||||
@@ -170,6 +179,15 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
## Authentication
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/11zi7sUJFoU"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/f4yAnVgcJqI"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
[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).
|
||||
|
||||
<Tabs
|
||||
@@ -531,6 +558,15 @@ const supabase = createClientComponentClient({ isSingleton: false })
|
||||
|
||||
### Server Component
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/SUS1t6Kq7-8"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
[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
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/B5TUzTKO9CE"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
[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
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/3kK-40z0DHI"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
[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.
|
||||
|
||||
<Tabs
|
||||
@@ -704,8 +758,9 @@ See [refreshing session example](/docs/guides/auth/auth-helpers/nextjs#refresh-s
|
||||
|
||||
## More examples
|
||||
|
||||
- [Full App Router repo](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs)
|
||||
- [Realtime](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs/app/realtime-posts.tsx)
|
||||
- [Cookie-based Auth and the Next.js 13 App Router (free course)](https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF)
|
||||
- [Full App Router example](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs)
|
||||
- [Realtime Subscriptions](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs/app/realtime-posts.tsx)
|
||||
- [Protected Routes](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs/app/[id]/page.tsx)
|
||||
- [Conditional Rendering in Client Components with SSR](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs/app/login-form.tsx)
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ async function signInWithGoogle() {
|
||||
queryParams: {
|
||||
access_type: 'offline',
|
||||
prompt: 'consent',
|
||||
hd: 'domain.com //google will also allowo OAuth logins to be restricted to a specified domain using the 'hd' parameter
|
||||
hd: 'domain.com', // google will also allow OAuth logins to be restricted to a specified domain using the 'hd' parameter
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@ We can reference the environment variable by using the `env()` function.
|
||||
|
||||
Inside of our `.env` file we add the environment variable as we normally would
|
||||
|
||||
```env
|
||||
```bash
|
||||
GITHUB_CLIENT_ID=""
|
||||
GITHUB_SECRET=""
|
||||
```
|
||||
|
||||
@@ -71,7 +71,7 @@ where team_id = 'NYM';
|
||||
```
|
||||
|
||||
```js
|
||||
const { data, error } = await supabase
|
||||
const { count, error } = await supabase
|
||||
.from('players')
|
||||
.select('*', { count: 'exact', head: true }) // exact, planned, or executed
|
||||
.eq('team_id', 'NYM')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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-----
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
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.
|
||||
|
||||
</Admonition>
|
||||
|
||||
Add the `AuthForm` component to your home page
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -9,7 +9,74 @@ There are several ways to use Supabase:
|
||||
|
||||
- [Supabase Cloud](https://app.supabase.com): you don't need to deploy anything. We will manage and scale your infrastructure.
|
||||
- [Docker](/docs/guides/self-hosting/docker): deploy to your own infrastructure.
|
||||
- Kubernetes: coming soon.
|
||||
|
||||
### Community
|
||||
|
||||
There are several community-driven projects to help you deploy Supabase. We encourage you to try them out and contribute back to the community.
|
||||
|
||||
<div className="grid md:grid-cols-12 gap-4 not-prose">
|
||||
{community.map((x) => (
|
||||
<div className="md:col-span-6 xl:col-span-3" key={x.href}>
|
||||
<Link href={x.href} passHref>
|
||||
<a>
|
||||
<GlassPanel title={x.name}>{x.description}</GlassPanel>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
export const community = [
|
||||
{
|
||||
name: 'Kubernetes',
|
||||
description: 'Helm charts to deploy a Supabase on Kubernetes.',
|
||||
href: 'https://github.com/supabase-community/supabase-kubernetes',
|
||||
},
|
||||
{
|
||||
name: 'Terraform',
|
||||
description: 'A community-driven Terraform Provider for Supabase.',
|
||||
href: 'https://github.com/supabase-community/supabase-terraform',
|
||||
},
|
||||
{
|
||||
name: 'Traefik',
|
||||
description: 'A self-hosted Supabase setup with Traefik as a reverse proxy.',
|
||||
href: 'https://github.com/supabase-community/supabase-traefik',
|
||||
},
|
||||
{
|
||||
name: 'AWS',
|
||||
description: 'A CloudFormation template for Supabase.',
|
||||
href: 'https://github.com/supabase-community/supabase-on-aws',
|
||||
},
|
||||
]
|
||||
|
||||
### Third-party
|
||||
|
||||
The following third-party providers have shown consistent support for the self-hosted version of Supabase:.
|
||||
|
||||
<div className="grid md:grid-cols-12 gap-4 not-prose">
|
||||
{external.map((x) => (
|
||||
<div className="md:col-span-6" key={x.href}>
|
||||
<Link href={x.href} passHref>
|
||||
<a>
|
||||
<GlassPanel title={x.name}>{x.description}</GlassPanel>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
export const external = [
|
||||
{
|
||||
name: 'Digital Ocean',
|
||||
description: 'Deploys using Terraform.',
|
||||
href: 'https://supabase-on-do.product-docs.pages.dev/developer-center/hosting-supabase-on-digitalocean/',
|
||||
},
|
||||
{
|
||||
name: 'StackGres',
|
||||
description: 'Deploys using Kubernetes.',
|
||||
href: 'https://stackgres.io/blog/running-supabase-on-top-of-stackgres/',
|
||||
},
|
||||
]
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -53,8 +120,8 @@ to run automatically when starting the database container.
|
||||
We recommend installing all extensions into an `extensions` schema. This will keep your API clean,
|
||||
since all tables in the `public` schema are exposed via the API.
|
||||
|
||||
```sql
|
||||
{/* prettier-ignore */}
|
||||
```sql
|
||||
create schema if not exists extensions;
|
||||
create extension if not exists "uuid-ossp" with schema extensions;
|
||||
create extension if not exists pgcrypto with schema extensions;
|
||||
@@ -146,15 +213,6 @@ Supabase is evolving fast, and we'll continue to improve the migration strategy
|
||||
|
||||
We realize that database migrations are difficult, and this is one of the problems we plan to make easy for developers.
|
||||
|
||||
## Deployment options
|
||||
|
||||
While Supabase officially supports Docker, we have several other deployment strategies managed by the community:
|
||||
|
||||
- [supabase-docker](/docs/guides/self-hosting/docker) (Official)
|
||||
- [supabase-kubernetes](https://github.com/supabase-community/supabase-kubernetes) (Unofficial)
|
||||
- [supabase-terraform](https://github.com/supabase-community/supabase-terraform) (Unofficial)
|
||||
- [supabase-traefik](https://github.com/supabase-community/supabase-traefik) (Unofficial)
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -3,22 +3,18 @@ import Layout from '~/layouts/DefaultGuideLayout'
|
||||
export const meta = {
|
||||
title: 'Self-Hosting with Docker',
|
||||
description: 'Learn how to configure and deploy Supabase with Docker.',
|
||||
subtitle: 'Learn how to configure and deploy Supabase with Docker.',
|
||||
}
|
||||
|
||||
Docker is the easiest way to get started with self-hosted Supabase.
|
||||
Docker is the easiest way to get started with self-hosted Supabase. This guide assumes you are running the command from the machine you intend to host from.
|
||||
|
||||
## Before you begin
|
||||
|
||||
You need the following installed in your system:
|
||||
You need the following installed in your system: [Git](https://git-scm.com/downloads) and Docker ([Windows](https://docs.docker.com/desktop/install/windows-install/), [MacOS](https://docs.docker.com/desktop/install/mac-install/), or [Linux](https://docs.docker.com/desktop/install/linux-install/)).
|
||||
|
||||
- [Docker](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/install/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
## Running Supabase
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Get the code
|
||||
|
||||
Checkout the docker directory in the Supabase repo:
|
||||
Running a self-hosted Supabase project is simple. Follow the steps below:
|
||||
|
||||
```sh
|
||||
# Get the code
|
||||
@@ -34,17 +30,23 @@ cp .env.example .env
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Now visit [http://localhost:3000](http://localhost:3000) to start using Supabase Studio.
|
||||
Now visit [localhost:3000](http://localhost:3000) to start using Supabase Studio.
|
||||
|
||||
That's everything you need to get started. The rest of this guide will help you to customize your setup.
|
||||
|
||||
## Securing your setup
|
||||
|
||||
While we provided you with some example secrets for getting started, you should NEVER deploy your Supabase setup using the defaults we have provided.
|
||||
|
||||
Follow these steps to secure your Docker setup. We strongly recommend using a [secrets manager](../self-hosting#managing-your-secrets) when deploying to production.
|
||||
|
||||
### Generate API Keys
|
||||
|
||||
Use your `JWT_SECRET` to generate a `anon` and `service` API keys using the [JWT generator](../self-hosting#api-keys).
|
||||
Create a new `JWT_SECRET` and store it securely.
|
||||
|
||||
We can use your JWT Secret to generate new `anon` and `service` API keys using the form below. Update the "JWT Secret" and then run "Generate JWT" once for the `SERVICE_KEY` and once for the `ANON_KEY`:
|
||||
|
||||
<JwtGenerator />
|
||||
|
||||
### Update API Keys
|
||||
|
||||
Replace the values in these files:
|
||||
|
||||
@@ -64,23 +66,45 @@ Update the `.env` file with your own secrets. In particular, these are required:
|
||||
- `SITE_URL`: the base URL of your site.
|
||||
- `SMTP_*`: mail server credentials. You can use any SMTP server.
|
||||
|
||||
### Securing the Dashboard
|
||||
## Exposing services
|
||||
|
||||
The Docker setup doesn't include a management database for managing users and logins. If you plan to deploy the Studio to the web we suggest you put it behind a web proxy with Basic Auth or hide it behind a VPN.
|
||||
The services running on the machine are not exposed to the internet by default. We recommend using a reverse proxy such as [NGINX](https://www.nginx.com/) or [Caddy](https://caddyserver.com/) if you want to expose the services publicly:
|
||||
|
||||
## Setting up Edge Functions
|
||||
1. Install Caddy using the official [instructions](https://caddyserver.com/docs/install).
|
||||
2. Modify the `Caddyfile` at `./docker/deploy/caddy/Caddyfile`.
|
||||
1. Replace `localhost` with your domain.
|
||||
2. Uncomment the "Dashboard" section if you want to expose the Supabase Dashboard. You **MUST** set a password for this to be secure.
|
||||
3. Run `caddy run --config ./docker/deploy/caddy/Caddyfile` to start Caddy.
|
||||
|
||||
You can now access your services at the following URLs:
|
||||
|
||||
- REST: `https://<your-domain>/proxy/rest/v1/`
|
||||
- Auth: `https://<your-domain>/proxy/auth/v1/`
|
||||
- Storage: `https://<your-domain>/proxy/storage/v1/`
|
||||
- Functions: `https://<your-domain>/proxy/functions/v1/`
|
||||
- Realtime: `https://<your-domain>/proxy/realtime/v1/`
|
||||
- Dashboard: `https://<your-domain>/` (if you uncommented the Dashboard section in the Caddyfile)
|
||||
|
||||
## Stop
|
||||
|
||||
You can stop Supabase by running `docker compose stop` in same directory as your `docker-compose.yml` file.
|
||||
|
||||
## Uninstall
|
||||
|
||||
You can stop Supabase by running `docker compose down -v` in same directory as your `docker-compose.yml` file.
|
||||
|
||||
## Advanced configuration
|
||||
|
||||
Each system can be [configured](../self-hosting#configuration) independently. Some of the most important configuration options are:
|
||||
|
||||
- Consider deploying the database to a different server than the rest of the services
|
||||
- Update Storage to use S3 instead of the filesystem backend
|
||||
- Configure Auth with a production-ready SMTP server
|
||||
|
||||
### Setting up Edge Functions
|
||||
|
||||
Your Functions are stored in `volumes/functions`. The default setup has a `hello` Function that you can invoke on `http://localhost:8000/functions/v1/hello`. You can add new Functions as `volumes/functions/<Function name>/index.ts`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Each system can be [configured](../self-hosting#configuration) to suit your particular use-case.
|
||||
|
||||
To keep the setup simple, we made some choices that may not be optimal for production:
|
||||
|
||||
- the database is in the same machine as the servers
|
||||
- Storage uses the filesystem backend instead of S3
|
||||
- Auth should be configured with a production-ready SMTP server
|
||||
|
||||
### Using an external database
|
||||
|
||||
@@ -112,19 +136,6 @@ However, you might miss important log messages such as database errors. Configur
|
||||
|
||||
By default, Storage backend is set to `file`, which is to use local files as the storage backend. To make it work on macOS, you need to choose `VirtioFS` as the Docker container file sharing implementation (in Docker Desktop -> Preferences -> General).
|
||||
|
||||
## Deploying
|
||||
|
||||
See the following guides to deploy Docker Compose setup using your preferred tool and platform:
|
||||
|
||||
- [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/)
|
||||
- [AWS Fargate](https://aws.amazon.com/blogs/containers/deploy-applications-on-amazon-ecs-using-docker-compose/)
|
||||
- [Using Kompose for Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/)
|
||||
|
||||
## Next steps
|
||||
|
||||
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
|
||||
- Sign in: [app.supabase.com](https://app.supabase.com)
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -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.
|
||||
|
||||
<Quote img="krrish-d.png" caption="Krrish D. - Co-Founder & CEO, Berri AI">
|
||||
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.
|
||||
</Quote>
|
||||
|
||||
## 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.
|
||||
|
||||
<Quote img="krrish-d.png" caption="Krrish D. - Co-Founder & CEO, Berri AI">
|
||||
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.
|
||||
</Quote>
|
||||
|
||||
## 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.
|
||||
|
||||
<Quote img="ishaan-jaffer.png" caption="Ishaan Jaffer - Co-Founder & CTO, Berri AI">
|
||||
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.
|
||||
</Quote>
|
||||
|
||||
## 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
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
import { remarkCodeHike } from '@code-hike/mdx'
|
||||
|
||||
declare module '@code-hike/mdx' {
|
||||
export type CodeHikeRemarkPlugin = typeof remarkCodeHike
|
||||
export type CodeHikeConfig = Parameters<CodeHikeRemarkPlugin>[0]
|
||||
}
|
||||
@@ -88,9 +88,9 @@ export default function ComputePricingModal({ showComputeModal, setShowComputeMo
|
||||
<td key={column.key} className="p-3">
|
||||
{column.key === 'dedicated' ? (
|
||||
column.value ? (
|
||||
<IconPricingIncludedCheck tier="Pro plan" />
|
||||
<IconPricingIncludedCheck plan="Pro plan" />
|
||||
) : (
|
||||
<IconPricingMinus tier="Free plan" />
|
||||
<IconPricingMinus plan="Free plan" />
|
||||
)
|
||||
) : (
|
||||
column.value
|
||||
@@ -124,9 +124,9 @@ export default function ComputePricingModal({ showComputeModal, setShowComputeMo
|
||||
>
|
||||
{column.key === 'dedicated' ? (
|
||||
column.value ? (
|
||||
<IconPricingIncludedCheck tier="Pro plan" />
|
||||
<IconPricingIncludedCheck plan="Pro plan" />
|
||||
) : (
|
||||
<IconPricingMinus tier="Free plan" />
|
||||
<IconPricingMinus plan="Free plan" />
|
||||
)
|
||||
) : (
|
||||
column.value
|
||||
|
||||
@@ -12,7 +12,7 @@ export const Check = () => (
|
||||
export const IconPricingIncludedCheck = (props: any) => (
|
||||
<span className="mx-auto">
|
||||
<Check />
|
||||
<span className="sr-only">Included in {props.tier}</span>
|
||||
<span className="sr-only">Included in {props.plan}</span>
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ export const IconPricingMinus = (props: any) => (
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Not included in {props.tier}</span>
|
||||
<span className="sr-only">Not included in {props.plan}</span>
|
||||
</>
|
||||
)
|
||||
|
||||
|
||||
@@ -48,35 +48,35 @@ export const PricingTableRowDesktop = (props: any) => {
|
||||
)}
|
||||
</th>
|
||||
|
||||
{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 (
|
||||
<td
|
||||
key={i}
|
||||
className={[
|
||||
`px-6 tier-${tierName}`,
|
||||
typeof tierValue === 'boolean' ? 'text-center' : '',
|
||||
`px-6 tier-${planName}`,
|
||||
typeof planValue === 'boolean' ? 'text-center' : '',
|
||||
].join(' ')}
|
||||
>
|
||||
{typeof tierValue === 'boolean' && tierValue === true ? (
|
||||
<IconPricingIncludedCheck tier={tierValue} />
|
||||
) : typeof tierValue === 'boolean' && tierValue === false ? (
|
||||
{typeof planValue === 'boolean' && planValue === true ? (
|
||||
<IconPricingIncludedCheck plan={planValue} />
|
||||
) : typeof planValue === 'boolean' && planValue === false ? (
|
||||
<div className="text-scale-900">
|
||||
<IconPricingMinus tier={tierValue} />
|
||||
<IconPricingMinus plan={planValue} />
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-scale-1200 text-xs dark:text-white flex items-center gap-3">
|
||||
{feat.tooltips?.[tierName] && (
|
||||
{feat.tooltips?.[planName] && (
|
||||
<span
|
||||
className="shrink-0 hover:text-scale-300 cursor-pointer transition-colors"
|
||||
data-tip={feat.tooltips[tierName]}
|
||||
data-tip={feat.tooltips[planName]}
|
||||
>
|
||||
<IconPricingInfo />
|
||||
</span>
|
||||
)}
|
||||
{tierValue}
|
||||
{planValue}
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
@@ -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) => {
|
||||
</span>
|
||||
</th>
|
||||
<td className="py-3 pr-4 text-right">
|
||||
{typeof feat.tiers[tier] === 'boolean' && feat.tiers[tier] === true ? (
|
||||
{typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === true ? (
|
||||
<div className="inline-block">
|
||||
<IconPricingIncludedCheck tier={tier} />
|
||||
<IconPricingIncludedCheck plan={plan} />
|
||||
</div>
|
||||
) : typeof feat.tiers[tier] === 'boolean' && feat.tiers[tier] === false ? (
|
||||
) : typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === false ? (
|
||||
<div className="inline-block">
|
||||
<IconPricingMinus tier={tier} />
|
||||
<IconPricingMinus plan={plan} />
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-scale-1200 block text-sm">{feat.tiers[tier]}</span>
|
||||
<span className="text-scale-1200 block text-sm">{feat.plans[plan]}</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
"text": "Storage",
|
||||
"url": "/storage"
|
||||
},
|
||||
{
|
||||
"text": "Vector",
|
||||
"url": "/vector"
|
||||
},
|
||||
{
|
||||
"text": "Pricing",
|
||||
"url": "/pricing"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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": "^13.0.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-html": "^15.0.1",
|
||||
"shared-data": "*",
|
||||
"swiper": "^6.5.0",
|
||||
"swr": "^0.5.4",
|
||||
"typescript": "^4.0.3",
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
+231
-206
@@ -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 (
|
||||
<div className="mt-8 px-4 mobile-header">
|
||||
<h2 className="gradient-text-brand-500 dark:gradient-text-brand-100 text-3xl font-medium uppercase font-mono">
|
||||
{tier}
|
||||
{plan}
|
||||
</h2>
|
||||
<div className="flex items-baseline gap-2">
|
||||
{from && <span className="text-scale-1200 text-base">From</span>}
|
||||
@@ -242,7 +159,7 @@ export default function IndexPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto flex max-w-7xl flex-col">
|
||||
<div className="mx-auto max-w-7xl flex flex-col">
|
||||
{/* <div className="absolute inset-0 shadow-sm bg-scale-200 h-3/5" /> */}
|
||||
|
||||
<div
|
||||
@@ -252,28 +169,28 @@ export default function IndexPage() {
|
||||
"
|
||||
>
|
||||
<div className="mx-auto max-w-md grid lg:max-w-6xl lg:grid-cols-3 gap-24 lg:gap-5">
|
||||
{tiers.map((tier) => (
|
||||
{plansExceptEnterprise.map((plan) => (
|
||||
<div
|
||||
key={`row-${tier.name}`}
|
||||
key={`row-${plan.name}`}
|
||||
className={[
|
||||
tier.name === 'Pro'
|
||||
plan.name === 'Pro'
|
||||
? 'bg-brand-1100 dark:bg-brand-900 border px-0.5 -mt-8 rounded-[6px]'
|
||||
: '',
|
||||
].join(' ')}
|
||||
>
|
||||
{tier.name === 'Pro' && (
|
||||
{plan.name === 'Pro' && (
|
||||
<p className="text-xs text-center py-2 text-white">Most Popular</p>
|
||||
)}
|
||||
<div
|
||||
key={tier.name}
|
||||
key={plan.name}
|
||||
className={[
|
||||
'flex flex-col overflow-hidden',
|
||||
tier.name === 'Pro' ? '' : 'border h-full rounded-[4px]',
|
||||
plan.name === 'Pro' ? '' : 'border h-full rounded-[4px]',
|
||||
].join(' ')}
|
||||
>
|
||||
<div
|
||||
className={`dark:bg-scale-300 bg-white px-8 pt-6 rounded-tr-[4px] rounded-tl-[4px] ${
|
||||
tier.name === 'Pro' ? 'rounded-tr-[4px] rounded-tl-[4px]' : ''
|
||||
plan.name === 'Pro' ? 'rounded-tr-[4px] rounded-tl-[4px]' : ''
|
||||
}`}
|
||||
>
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
@@ -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}
|
||||
</h3>
|
||||
{tier.nameBadge && (
|
||||
<span className="bg-scale-300 text-scale-900 dark:bg-scale-400 dark:text-scale-1100 rounded-md bg-opacity-10 py-0.5 px-2 text-xs [background-image: none]">
|
||||
{tier.nameBadge}
|
||||
{plan.nameBadge && (
|
||||
<span className="bg-brand-500 text-brand-1100 rounded-md bg-opacity-30 py-0.5 px-2 text-xs">
|
||||
{plan.nameBadge}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-scale-1100 my-4 h-[55px] text-sm border-b dark:border-scale-500 pb-4 lg:pr-20">
|
||||
{tier.description}
|
||||
<p className="text-scale-1100 my-4 text-sm border-b dark:border-scale-500 pb-4 2xl:pr-4">
|
||||
{plan.description}
|
||||
</p>
|
||||
|
||||
<div
|
||||
className="
|
||||
text-scale-1200 flex items-baseline
|
||||
text-5xl
|
||||
font-normal
|
||||
lg:text-4xl
|
||||
xl:text-4xl
|
||||
border-b
|
||||
dark:border-scale-500
|
||||
pt-4
|
||||
pb-8
|
||||
min-h-[175px]
|
||||
"
|
||||
className={`
|
||||
text-scale-1200 flex items-baseline
|
||||
text-5xl
|
||||
font-normal
|
||||
lg:text-4xl
|
||||
xl:text-4xl
|
||||
border-b
|
||||
dark:border-scale-500
|
||||
min-h-[175px] ${plan.priceLabel ? 'pt-6' : 'pt-10'}`}
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-end gap-2">
|
||||
<div>
|
||||
<p className="text-scale-900 ml-1 text-xs font-normal">
|
||||
{tier.priceLabel}
|
||||
</p>
|
||||
<p
|
||||
className={`mt-2 gradient-text-scale-500 dark:gradient-text-scale-100 pb-1 ${
|
||||
tier.name !== 'Enterprise' ? 'text-5xl' : 'text-4xl'
|
||||
}`}
|
||||
>
|
||||
{tier.name !== 'Enterprise' && '$'}
|
||||
{tier.priceMonthly}
|
||||
</p>
|
||||
{tier.costUnit && (
|
||||
<p className="text-scale-900 mt-0.5 text-xs">{tier.costUnit}</p>
|
||||
{plan.priceLabel && (
|
||||
<p className="text-scale-900 ml-1 text-xs font-normal">
|
||||
{plan.priceLabel}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{tier.warning && (
|
||||
<div className="flex items-end">
|
||||
<p
|
||||
className={`mt-2 gradient-text-scale-500 dark:gradient-text-scale-100 pb-1 ${
|
||||
plan.name !== 'Enterprise' ? 'text-5xl' : 'text-4xl'
|
||||
}`}
|
||||
>
|
||||
${plan.priceMonthly}
|
||||
</p>
|
||||
<p className="text-scale-900 mb-1.5 ml-1 text-xs">
|
||||
{plan.costUnit}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{plan.warning && (
|
||||
<p className="-mt-2">
|
||||
<span className="bg-brand-500 text-brand-1100 rounded-md bg-opacity-30 py-0.5 px-2 text-xs ">
|
||||
{tier.warning}
|
||||
<span className="bg-scale-200 text-brand-1100 border shadow-sm rounded-md bg-opacity-30 py-0.5 px-2 text-xs">
|
||||
{plan.warning}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
@@ -342,18 +260,18 @@ export default function IndexPage() {
|
||||
<div
|
||||
className={[
|
||||
`dark:border-scale-400 dark:bg-scale-300 flex h-full rounded-bl-[4px] rounded-br-[4px] flex-1 flex-col bg-white px-8 py-6`,
|
||||
tier.name === 'Pro' ? 'mb-0.5 rounded-bl-[4px] rounded-br-[4px]' : '',
|
||||
plan.name === 'Pro' ? 'mb-0.5 rounded-bl-[4px] rounded-br-[4px]' : '',
|
||||
].join(' ')}
|
||||
>
|
||||
{tier.preface && (
|
||||
<p className="text-scale-1100 text-xs mt-2 mb-4">{tier.preface}</p>
|
||||
{plan.preface && (
|
||||
<p className="text-scale-1100 text-xs mt-2 mb-4">{plan.preface}</p>
|
||||
)}
|
||||
{/* <p className="text-scale-900 text-sm">Included with plan:</p> */}
|
||||
<ul role="list" className="text-xs text-scale-1000">
|
||||
{tier.features.map((feature) => (
|
||||
{plan.features.map((feature) => (
|
||||
<li key={feature} className="flex items-center py-2 first:mt-0">
|
||||
<IconCheck
|
||||
className="text-brand-900 h-4 w-4 "
|
||||
className="text-brand-900 h-4 w-4"
|
||||
aria-hidden="true"
|
||||
strokeWidth={3}
|
||||
/>
|
||||
@@ -365,15 +283,13 @@ export default function IndexPage() {
|
||||
|
||||
<div className="flex flex-col gap-6 mt-auto prose">
|
||||
<div className="space-y-2 mt-12">
|
||||
{tier.additional && <p className="text-sm">{tier.additional}</p>}
|
||||
{tier.scale && <p className="text-xs">{tier.scale}</p>}
|
||||
{tier.shutdown && (
|
||||
<p className="text-scale-1000 text-xs">{tier.shutdown}</p>
|
||||
{plan.footer && (
|
||||
<p className="text-xs whitespace-pre-wrap">{plan.footer}</p>
|
||||
)}
|
||||
</div>
|
||||
<a href={tier.href}>
|
||||
<a href={plan.href}>
|
||||
<Button block size="small">
|
||||
{tier.cta}
|
||||
{plan.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
@@ -384,6 +300,51 @@ export default function IndexPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-md lg:max-w-6xl grid grid-cols-1 lg:grid-cols-3 mx-auto border bg-scale-100 rounded-md p-8 lg:px-0 mt-8 gap-x-5">
|
||||
<div className="flex flex-col justify-center lg:px-8">
|
||||
<div>
|
||||
<h3
|
||||
className="gradient-text-brand-500 dark:gradient-text-brand-100 text-2xl font-normal
|
||||
uppercase flex items-center gap-4 font-mono"
|
||||
>
|
||||
{planEnterprise.name}
|
||||
</h3>
|
||||
<p className="text-scale-1100 my-4 text-sm pb-2 2xl:pr-4">
|
||||
{planEnterprise.description}
|
||||
</p>
|
||||
|
||||
<a href={planEnterprise.href} className="hidden lg:block">
|
||||
<Button type="default" size="small">
|
||||
{planEnterprise.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center lg:col-span-2">
|
||||
<ul role="list" className="text-xs text-scale-1000 lg:grid lg:grid-cols-2 lg:gap-x-5">
|
||||
{planEnterprise.features.map((feature) => (
|
||||
<li key={feature} className="flex items-center py-2 first:mt-0">
|
||||
<IconCheck
|
||||
className="text-brand-900 h-4 w-4 "
|
||||
aria-hidden="true"
|
||||
strokeWidth={3}
|
||||
/>
|
||||
<span className="dark:text-scale-1200 mb-0 ml-3 ">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<a href={planEnterprise.href} className="visible lg:hidden mt-8">
|
||||
<Button block type="default" size="small">
|
||||
{planEnterprise.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center mt-24">
|
||||
<a href="#compare-plans">
|
||||
<Button size="tiny" type="default">
|
||||
@@ -486,12 +447,10 @@ export default function IndexPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="">
|
||||
<img
|
||||
className="w-full"
|
||||
src={`${basePath}/images/pricing/spend-cap${isDarkMode ? '' : '-light'}.png`}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
className="w-full"
|
||||
src={`${basePath}/images/pricing/spend-cap${isDarkMode ? '' : '-light'}.png`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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)}
|
||||
>
|
||||
<Select.Option value="Free">Free</Select.Option>
|
||||
<Select.Option value="Pro">Pro</Select.Option>
|
||||
<Select.Option value="Team">Team</Select.Option>
|
||||
<Select.Option value="Enterprise">Enterprise</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
{activeMobileTier === 'Free' && (
|
||||
{activeMobilePlan === 'Free' && (
|
||||
<>
|
||||
<MobileHeader
|
||||
tier="Free"
|
||||
plan="Free"
|
||||
price={'0'}
|
||||
priceDescription={'/mo'}
|
||||
description={'Perfect for hobby projects and experiments'}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.database}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={Solutions['database'].icon}
|
||||
sectionId="database"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.auth}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={Solutions['authentication'].icon}
|
||||
sectionId="auth"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.storage}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={Solutions['storage'].icon}
|
||||
sectionId="storage"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.realtime}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={Solutions['realtime'].icon}
|
||||
sectionId="realtime"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing['edge-functions']}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={Solutions['edge-functions'].icon}
|
||||
sectionId="edge-functions"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.dashboard}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={pricing.dashboard.icon}
|
||||
sectionId="dashboard"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.security}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={pricing.security.icon}
|
||||
sectionId="security"
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.support}
|
||||
tier={'free'}
|
||||
plan={'free'}
|
||||
icon={pricing.support.icon}
|
||||
sectionId="support"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeMobileTier === 'Pro' && (
|
||||
{activeMobilePlan === 'Pro' && (
|
||||
<>
|
||||
<MobileHeader
|
||||
tier="Pro"
|
||||
plan="Pro"
|
||||
from={false}
|
||||
price={'25'}
|
||||
priceDescription={'/mo + additional use'}
|
||||
@@ -599,51 +559,103 @@ export default function IndexPage() {
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.database}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={Solutions['database'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.auth}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={Solutions['authentication'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.storage}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={Solutions['storage'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.realtime}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={Solutions['realtime'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing['edge-functions']}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={Solutions['edge-functions'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.dashboard}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={pricing.dashboard.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.security}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={pricing.security.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.support}
|
||||
tier={'pro'}
|
||||
plan={'pro'}
|
||||
icon={pricing.support.icon}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeMobileTier === 'Enterprise' && (
|
||||
{activeMobilePlan === 'Team' && (
|
||||
<>
|
||||
<MobileHeader
|
||||
tier="Enterprise"
|
||||
plan="Team"
|
||||
from={false}
|
||||
price={'599'}
|
||||
priceDescription={'/mo + additional use'}
|
||||
description={'Collaborate with different permissions and access patterns'}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.database}
|
||||
plan={'team'}
|
||||
icon={Solutions['database'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.auth}
|
||||
plan={'team'}
|
||||
icon={Solutions['authentication'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.storage}
|
||||
plan={'team'}
|
||||
icon={Solutions['storage'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.realtime}
|
||||
plan={'team'}
|
||||
icon={Solutions['realtime'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing['edge-functions']}
|
||||
plan={'team'}
|
||||
icon={Solutions['edge-functions'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.dashboard}
|
||||
plan={'team'}
|
||||
icon={pricing.dashboard.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.security}
|
||||
plan={'team'}
|
||||
icon={pricing.security.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.support}
|
||||
plan={'team'}
|
||||
icon={pricing.support.icon}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeMobilePlan === 'Enterprise' && (
|
||||
<>
|
||||
<MobileHeader
|
||||
plan="Enterprise"
|
||||
price={'Contact us for a quote'}
|
||||
priceDescription={''}
|
||||
description={
|
||||
@@ -653,42 +665,42 @@ export default function IndexPage() {
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.database}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={Solutions['database'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.auth}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={Solutions['authentication'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.storage}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={Solutions['storage'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.realtime}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={Solutions['realtime'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing['edge-functions']}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={Solutions['edge-functions'].icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.dashboard}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={pricing.dashboard.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.security}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={pricing.security.icon}
|
||||
/>
|
||||
<PricingTableRowMobile
|
||||
category={pricing.support}
|
||||
tier={'enterprise'}
|
||||
plan={'enterprise'}
|
||||
icon={pricing.support.icon}
|
||||
/>
|
||||
</>
|
||||
@@ -712,14 +724,14 @@ export default function IndexPage() {
|
||||
></div>
|
||||
</th>
|
||||
|
||||
{tiers.map((tier) => (
|
||||
{plans.map((plan) => (
|
||||
<th
|
||||
className="text-scale-1200 w-1/4 px-6 pr-2 pt-2 pb-2 text-left text-sm font-normal"
|
||||
scope="col"
|
||||
key={tier.name}
|
||||
key={plan.name}
|
||||
>
|
||||
<h3 className="gradient-text-brand-500 dark:gradient-text-brand-100 text-2xl font-mono font-normal uppercase flex items-center gap-4">
|
||||
{tier.name}
|
||||
{plan.name}
|
||||
</h3>
|
||||
<div
|
||||
className="h-0.25 absolute bottom-0 left-0 w-full"
|
||||
@@ -735,13 +747,13 @@ export default function IndexPage() {
|
||||
scope="col"
|
||||
></th>
|
||||
|
||||
{tiers.map((tier) => (
|
||||
{plans.map((plan) => (
|
||||
<th
|
||||
className="text-scale-1200 w-1/4 px-6 pt-2 pb-2 text-left text-sm font-normal"
|
||||
scope="col"
|
||||
key={`th-${tier.name}`}
|
||||
key={`th-${plan.name}`}
|
||||
>
|
||||
<p className="p text-sm border-b border-scale-700 pb-4">{tier.description}</p>
|
||||
<p className="p text-sm border-b border-scale-700 pb-4">{plan.description}</p>
|
||||
<div
|
||||
className="h-0.25 absolute bottom-0 left-0 w-full"
|
||||
style={{ height: '1px' }}
|
||||
@@ -750,47 +762,50 @@ export default function IndexPage() {
|
||||
))}
|
||||
</tr>
|
||||
<tbody className="border-scale-700 dark:border-scale-400 divide-scale-700 dark:divide-scale-400 divide-y">
|
||||
<tr className="">
|
||||
<tr>
|
||||
<th
|
||||
className="text-scale-900 px-6 py-8 text-left align-top text-sm font-medium dark:text-white"
|
||||
scope="row"
|
||||
></th>
|
||||
|
||||
{tiers.map((tier) => (
|
||||
<td className="h-full px-6 py-2 align-top" key={`price-${tier.name}`}>
|
||||
{plans.map((plan) => (
|
||||
<td className="h-full px-6 py-2 align-top" key={`price-${plan.name}`}>
|
||||
<div className="relative table h-full w-full">
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<>
|
||||
<span
|
||||
className={`text-scale-1200 ${
|
||||
tier.name !== 'Enterprise' ? 'text-5xl' : 'text-4xl'
|
||||
plan.name !== 'Enterprise' ? 'text-5xl' : 'text-4xl'
|
||||
}`}
|
||||
>
|
||||
{tier.name !== 'Enterprise' && '$'}
|
||||
{tier.priceMonthly}
|
||||
{plan.name !== 'Enterprise' && '$'}
|
||||
{plan.priceMonthly}
|
||||
</span>
|
||||
{tier.name !== 'Enterprise' && (
|
||||
<p className="p text-xs mt-1">per project per month</p>
|
||||
{['Pro', 'Free'].includes(plan.name) && (
|
||||
<p className="p text-xs mt-1">per month</p>
|
||||
)}
|
||||
{['Team'].includes(plan.name) && (
|
||||
<p className="p text-xs mt-1">per month</p>
|
||||
)}
|
||||
</>
|
||||
|
||||
{tier.warning && (
|
||||
{plan.warning && (
|
||||
<p className="-mt-2">
|
||||
<span className="bg-brand-500 text-brand-1100 rounded-md bg-opacity-30 py-0.5 px-2 text-xs ">
|
||||
{tier.warning}
|
||||
<span className="bg-scale-100 text-brand-1100 border shadow-sm rounded-md bg-opacity-30 py-0.5 px-2 text-xs">
|
||||
{plan.warning}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className={tier.name === 'Enterprise' ? 'mt-auto' : 'mt-8'}>
|
||||
<Link href={tier.href} as={tier.href}>
|
||||
<div className={plan.name === 'Enterprise' ? 'mt-auto' : 'mt-8'}>
|
||||
<Link href={plan.href} as={plan.href}>
|
||||
<a>
|
||||
<Button
|
||||
size="tiny"
|
||||
type={tier.name === 'Enterprise' ? 'default' : 'primary'}
|
||||
type={plan.name === 'Enterprise' ? 'default' : 'primary'}
|
||||
block
|
||||
>
|
||||
{tier.cta}
|
||||
{plan.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
@@ -875,7 +890,7 @@ export default function IndexPage() {
|
||||
</td>
|
||||
|
||||
<td className="px-6 pt-5">
|
||||
<Link href="https://forms.supabase.com/enterprise">
|
||||
<Link href="https://forms.supabase.com/team">
|
||||
<a>
|
||||
<Button size="tiny" type="primary" block>
|
||||
Contact us
|
||||
@@ -883,6 +898,16 @@ export default function IndexPage() {
|
||||
</a>
|
||||
</Link>
|
||||
</td>
|
||||
|
||||
<td className="px-6 pt-5">
|
||||
<Link href="https://forms.supabase.com/enterprise">
|
||||
<a>
|
||||
<Button size="tiny" type="default" block>
|
||||
Contact us
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 297 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 328 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,19 @@
|
||||
localhost
|
||||
|
||||
## API Server
|
||||
## You can change this route to anything, however if you use /api/ then you will have conflicts
|
||||
## with the NextJS API routes in the Dashboard
|
||||
handle_path /proxy/* {
|
||||
uri replace /proxy/ /
|
||||
reverse_proxy 127.0.0.1:8000
|
||||
}
|
||||
|
||||
# ## Dashboard
|
||||
# ## MAKE SURE YOU CHANGE THE PASSWORD BELOW BEFORE UNCOMMENTING THIS SECTION.
|
||||
# ## You can create a new password by running `caddy hash-password`
|
||||
# handle_path /* {
|
||||
# reverse_proxy 127.0.0.1:3000
|
||||
# basicauth /* {
|
||||
# supabase $2a$14$24w8H5T3D4hC74y6rdxgYOYqTna7K.zWbts/AheHuilnRrdPFGGhK ## IMPORTANT: CHANGE THIS PASSWORD
|
||||
# }
|
||||
# }
|
||||
@@ -0,0 +1,356 @@
|
||||
|
||||
|
||||
What I Worked On
|
||||
|
||||
February 2021
|
||||
|
||||
Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep.
|
||||
|
||||
The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights.
|
||||
|
||||
The language we used was an early version of Fortran. You had to type programs on punch cards, then stack them in the card reader and press a button to load the program into memory and run it. The result would ordinarily be to print something on the spectacularly loud printer.
|
||||
|
||||
I was puzzled by the 1401. I couldn't figure out what to do with it. And in retrospect there's not much I could have done with it. The only form of input to programs was data stored on punched cards, and I didn't have any data stored on punched cards. The only other option was to do things that didn't rely on any input, like calculate approximations of pi, but I didn't know enough math to do anything interesting of that type. So I'm not surprised I can't remember any programs I wrote, because they can't have done much. My clearest memory is of the moment I learned it was possible for programs not to terminate, when one of mine didn't. On a machine without time-sharing, this was a social as well as a technical error, as the data center manager's expression made clear.
|
||||
|
||||
With microcomputers, everything changed. Now you could have a computer sitting right in front of you, on a desk, that could respond to your keystrokes as it was running instead of just churning through a stack of punch cards and then stopping. [1]
|
||||
|
||||
The first of my friends to get a microcomputer built it himself. It was sold as a kit by Heathkit. I remember vividly how impressed and envious I felt watching him sitting in front of it, typing programs right into the computer.
|
||||
|
||||
Computers were expensive in those days and it took me years of nagging before I convinced my father to buy one, a TRS-80, in about 1980. The gold standard then was the Apple II, but a TRS-80 was good enough. This was when I really started programming. I wrote simple games, a program to predict how high my model rockets would fly, and a word processor that my father used to write at least one book. There was only room in memory for about 2 pages of text, so he'd write 2 pages at a time and then print them out, but it was a lot better than a typewriter.
|
||||
|
||||
Though I liked programming, I didn't plan to study it in college. In college I was going to study philosophy, which sounded much more powerful. It seemed, to my naive high school self, to be the study of the ultimate truths, compared to which the things studied in other fields would be mere domain knowledge. What I discovered when I got to college was that the other fields took up so much of the space of ideas that there wasn't much left for these supposed ultimate truths. All that seemed left for philosophy were edge cases that people in other fields felt could safely be ignored.
|
||||
|
||||
I couldn't have put this into words when I was 18. All I knew at the time was that I kept taking philosophy courses and they kept being boring. So I decided to switch to AI.
|
||||
|
||||
AI was in the air in the mid 1980s, but there were two things especially that made me want to work on it: a novel by Heinlein called The Moon is a Harsh Mistress, which featured an intelligent computer called Mike, and a PBS documentary that showed Terry Winograd using SHRDLU. I haven't tried rereading The Moon is a Harsh Mistress, so I don't know how well it has aged, but when I read it I was drawn entirely into its world. It seemed only a matter of time before we'd have Mike, and when I saw Winograd using SHRDLU, it seemed like that time would be a few years at most. All you had to do was teach SHRDLU more words.
|
||||
|
||||
There weren't any classes in AI at Cornell then, not even graduate classes, so I started trying to teach myself. Which meant learning Lisp, since in those days Lisp was regarded as the language of AI. The commonly used programming languages then were pretty primitive, and programmers' ideas correspondingly so. The default language at Cornell was a Pascal-like language called PL/I, and the situation was similar elsewhere. Learning Lisp expanded my concept of a program so fast that it was years before I started to have a sense of where the new limits were. This was more like it; this was what I had expected college to do. It wasn't happening in a class, like it was supposed to, but that was ok. For the next couple years I was on a roll. I knew what I was going to do.
|
||||
|
||||
For my undergraduate thesis, I reverse-engineered SHRDLU. My God did I love working on that program. It was a pleasing bit of code, but what made it even more exciting was my belief — hard to imagine now, but not unique in 1985 — that it was already climbing the lower slopes of intelligence.
|
||||
|
||||
I had gotten into a program at Cornell that didn't make you choose a major. You could take whatever classes you liked, and choose whatever you liked to put on your degree. I of course chose "Artificial Intelligence." When I got the actual physical diploma, I was dismayed to find that the quotes had been included, which made them read as scare-quotes. At the time this bothered me, but now it seems amusingly accurate, for reasons I was about to discover.
|
||||
|
||||
I applied to 3 grad schools: MIT and Yale, which were renowned for AI at the time, and Harvard, which I'd visited because Rich Draves went there, and was also home to Bill Woods, who'd invented the type of parser I used in my SHRDLU clone. Only Harvard accepted me, so that was where I went.
|
||||
|
||||
I don't remember the moment it happened, or if there even was a specific moment, but during the first year of grad school I realized that AI, as practiced at the time, was a hoax. By which I mean the sort of AI in which a program that's told "the dog is sitting on the chair" translates this into some formal representation and adds it to the list of things it knows.
|
||||
|
||||
What these programs really showed was that there's a subset of natural language that's a formal language. But a very proper subset. It was clear that there was an unbridgeable gap between what they could do and actually understanding natural language. It was not, in fact, simply a matter of teaching SHRDLU more words. That whole way of doing AI, with explicit data structures representing concepts, was not going to work. Its brokenness did, as so often happens, generate a lot of opportunities to write papers about various band-aids that could be applied to it, but it was never going to get us Mike.
|
||||
|
||||
So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp. I knew from experience that Lisp was interesting for its own sake and not just for its association with AI, even though that was the main reason people cared about it at the time. So I decided to focus on Lisp. In fact, I decided to write a book about Lisp hacking. It's scary to think how little I knew about Lisp hacking when I started writing that book. But there's nothing like writing a book about something to help you learn it. The book, On Lisp, wasn't published till 1993, but I wrote much of it in grad school.
|
||||
|
||||
Computer Science is an uneasy alliance between two halves, theory and systems. The theory people prove things, and the systems people build things. I wanted to build things. I had plenty of respect for theory — indeed, a sneaking suspicion that it was the more admirable of the two halves — but building things seemed so much more exciting.
|
||||
|
||||
The problem with systems work, though, was that it didn't last. Any program you wrote today, no matter how good, would be obsolete in a couple decades at best. People might mention your software in footnotes, but no one would actually use it. And indeed, it would seem very feeble work. Only people with a sense of the history of the field would even realize that, in its time, it had been good.
|
||||
|
||||
There were some surplus Xerox Dandelions floating around the computer lab at one point. Anyone who wanted one to play around with could have one. I was briefly tempted, but they were so slow by present standards; what was the point? No one else wanted one either, so off they went. That was what happened to systems work.
|
||||
|
||||
I wanted not just to build things, but to build things that would last.
|
||||
|
||||
In this dissatisfied state I went in 1988 to visit Rich Draves at CMU, where he was in grad school. One day I went to visit the Carnegie Institute, where I'd spent a lot of time as a kid. While looking at a painting there I realized something that might seem obvious, but was a big surprise to me. There, right on the wall, was something you could make that would last. Paintings didn't become obsolete. Some of the best ones were hundreds of years old.
|
||||
|
||||
And moreover this was something you could make a living doing. Not as easily as you could by writing software, of course, but I thought if you were really industrious and lived really cheaply, it had to be possible to make enough to survive. And as an artist you could be truly independent. You wouldn't have a boss, or even need to get research funding.
|
||||
|
||||
I had always liked looking at paintings. Could I make them? I had no idea. I'd never imagined it was even possible. I knew intellectually that people made art — that it didn't just appear spontaneously — but it was as if the people who made it were a different species. They either lived long ago or were mysterious geniuses doing strange things in profiles in Life magazine. The idea of actually being able to make art, to put that verb before that noun, seemed almost miraculous.
|
||||
|
||||
That fall I started taking art classes at Harvard. Grad students could take classes in any department, and my advisor, Tom Cheatham, was very easy going. If he even knew about the strange classes I was taking, he never said anything.
|
||||
|
||||
So now I was in a PhD program in computer science, yet planning to be an artist, yet also genuinely in love with Lisp hacking and working away at On Lisp. In other words, like many a grad student, I was working energetically on multiple projects that were not my thesis.
|
||||
|
||||
I didn't see a way out of this situation. I didn't want to drop out of grad school, but how else was I going to get out? I remember when my friend Robert Morris got kicked out of Cornell for writing the internet worm of 1988, I was envious that he'd found such a spectacular way to get out of grad school.
|
||||
|
||||
Then one day in April 1990 a crack appeared in the wall. I ran into professor Cheatham and he asked if I was far enough along to graduate that June. I didn't have a word of my dissertation written, but in what must have been the quickest bit of thinking in my life, I decided to take a shot at writing one in the 5 weeks or so that remained before the deadline, reusing parts of On Lisp where I could, and I was able to respond, with no perceptible delay "Yes, I think so. I'll give you something to read in a few days."
|
||||
|
||||
I picked applications of continuations as the topic. In retrospect I should have written about macros and embedded languages. There's a whole world there that's barely been explored. But all I wanted was to get out of grad school, and my rapidly written dissertation sufficed, just barely.
|
||||
|
||||
Meanwhile I was applying to art schools. I applied to two: RISD in the US, and the Accademia di Belli Arti in Florence, which, because it was the oldest art school, I imagined would be good. RISD accepted me, and I never heard back from the Accademia, so off to Providence I went.
|
||||
|
||||
I'd applied for the BFA program at RISD, which meant in effect that I had to go to college again. This was not as strange as it sounds, because I was only 25, and art schools are full of people of different ages. RISD counted me as a transfer sophomore and said I had to do the foundation that summer. The foundation means the classes that everyone has to take in fundamental subjects like drawing, color, and design.
|
||||
|
||||
Toward the end of the summer I got a big surprise: a letter from the Accademia, which had been delayed because they'd sent it to Cambridge England instead of Cambridge Massachusetts, inviting me to take the entrance exam in Florence that fall. This was now only weeks away. My nice landlady let me leave my stuff in her attic. I had some money saved from consulting work I'd done in grad school; there was probably enough to last a year if I lived cheaply. Now all I had to do was learn Italian.
|
||||
|
||||
Only stranieri (foreigners) had to take this entrance exam. In retrospect it may well have been a way of excluding them, because there were so many stranieri attracted by the idea of studying art in Florence that the Italian students would otherwise have been outnumbered. I was in decent shape at painting and drawing from the RISD foundation that summer, but I still don't know how I managed to pass the written exam. I remember that I answered the essay question by writing about Cezanne, and that I cranked up the intellectual level as high as I could to make the most of my limited vocabulary. [2]
|
||||
|
||||
I'm only up to age 25 and already there are such conspicuous patterns. Here I was, yet again about to attend some august institution in the hopes of learning about some prestigious subject, and yet again about to be disappointed. The students and faculty in the painting department at the Accademia were the nicest people you could imagine, but they had long since arrived at an arrangement whereby the students wouldn't require the faculty to teach anything, and in return the faculty wouldn't require the students to learn anything. And at the same time all involved would adhere outwardly to the conventions of a 19th century atelier. We actually had one of those little stoves, fed with kindling, that you see in 19th century studio paintings, and a nude model sitting as close to it as possible without getting burned. Except hardly anyone else painted her besides me. The rest of the students spent their time chatting or occasionally trying to imitate things they'd seen in American art magazines.
|
||||
|
||||
Our model turned out to live just down the street from me. She made a living from a combination of modelling and making fakes for a local antique dealer. She'd copy an obscure old painting out of a book, and then he'd take the copy and maltreat it to make it look old. [3]
|
||||
|
||||
While I was a student at the Accademia I started painting still lives in my bedroom at night. These paintings were tiny, because the room was, and because I painted them on leftover scraps of canvas, which was all I could afford at the time. Painting still lives is different from painting people, because the subject, as its name suggests, can't move. People can't sit for more than about 15 minutes at a time, and when they do they don't sit very still. So the traditional m.o. for painting people is to know how to paint a generic person, which you then modify to match the specific person you're painting. Whereas a still life you can, if you want, copy pixel by pixel from what you're seeing. You don't want to stop there, of course, or you get merely photographic accuracy, and what makes a still life interesting is that it's been through a head. You want to emphasize the visual cues that tell you, for example, that the reason the color changes suddenly at a certain point is that it's the edge of an object. By subtly emphasizing such things you can make paintings that are more realistic than photographs not just in some metaphorical sense, but in the strict information-theoretic sense. [4]
|
||||
|
||||
I liked painting still lives because I was curious about what I was seeing. In everyday life, we aren't consciously aware of much we're seeing. Most visual perception is handled by low-level processes that merely tell your brain "that's a water droplet" without telling you details like where the lightest and darkest points are, or "that's a bush" without telling you the shape and position of every leaf. This is a feature of brains, not a bug. In everyday life it would be distracting to notice every leaf on every bush. But when you have to paint something, you have to look more closely, and when you do there's a lot to see. You can still be noticing new things after days of trying to paint something people usually take for granted, just as you can after days of trying to write an essay about something people usually take for granted.
|
||||
|
||||
This is not the only way to paint. I'm not 100% sure it's even a good way to paint. But it seemed a good enough bet to be worth trying.
|
||||
|
||||
Our teacher, professor Ulivi, was a nice guy. He could see I worked hard, and gave me a good grade, which he wrote down in a sort of passport each student had. But the Accademia wasn't teaching me anything except Italian, and my money was running out, so at the end of the first year I went back to the US.
|
||||
|
||||
I wanted to go back to RISD, but I was now broke and RISD was very expensive, so I decided to get a job for a year and then return to RISD the next fall. I got one at a company called Interleaf, which made software for creating documents. You mean like Microsoft Word? Exactly. That was how I learned that low end software tends to eat high end software. But Interleaf still had a few years to live yet. [5]
|
||||
|
||||
Interleaf had done something pretty bold. Inspired by Emacs, they'd added a scripting language, and even made the scripting language a dialect of Lisp. Now they wanted a Lisp hacker to write things in it. This was the closest thing I've had to a normal job, and I hereby apologize to my boss and coworkers, because I was a bad employee. Their Lisp was the thinnest icing on a giant C cake, and since I didn't know C and didn't want to learn it, I never understood most of the software. Plus I was terribly irresponsible. This was back when a programming job meant showing up every day during certain working hours. That seemed unnatural to me, and on this point the rest of the world is coming around to my way of thinking, but at the time it caused a lot of friction. Toward the end of the year I spent much of my time surreptitiously working on On Lisp, which I had by this time gotten a contract to publish.
|
||||
|
||||
The good part was that I got paid huge amounts of money, especially by art student standards. In Florence, after paying my part of the rent, my budget for everything else had been $7 a day. Now I was getting paid more than 4 times that every hour, even when I was just sitting in a meeting. By living cheaply I not only managed to save enough to go back to RISD, but also paid off my college loans.
|
||||
|
||||
I learned some useful things at Interleaf, though they were mostly about what not to do. I learned that it's better for technology companies to be run by product people than sales people (though sales is a real skill and people who are good at it are really good at it), that it leads to bugs when code is edited by too many people, that cheap office space is no bargain if it's depressing, that planned meetings are inferior to corridor conversations, that big, bureaucratic customers are a dangerous source of money, and that there's not much overlap between conventional office hours and the optimal time for hacking, or conventional offices and the optimal place for it.
|
||||
|
||||
But the most important thing I learned, and which I used in both Viaweb and Y Combinator, is that the low end eats the high end: that it's good to be the "entry level" option, even though that will be less prestigious, because if you're not, someone else will be, and will squash you against the ceiling. Which in turn means that prestige is a danger sign.
|
||||
|
||||
When I left to go back to RISD the next fall, I arranged to do freelance work for the group that did projects for customers, and this was how I survived for the next several years. When I came back to visit for a project later on, someone told me about a new thing called HTML, which was, as he described it, a derivative of SGML. Markup language enthusiasts were an occupational hazard at Interleaf and I ignored him, but this HTML thing later became a big part of my life.
|
||||
|
||||
In the fall of 1992 I moved back to Providence to continue at RISD. The foundation had merely been intro stuff, and the Accademia had been a (very civilized) joke. Now I was going to see what real art school was like. But alas it was more like the Accademia than not. Better organized, certainly, and a lot more expensive, but it was now becoming clear that art school did not bear the same relationship to art that medical school bore to medicine. At least not the painting department. The textile department, which my next door neighbor belonged to, seemed to be pretty rigorous. No doubt illustration and architecture were too. But painting was post-rigorous. Painting students were supposed to express themselves, which to the more worldly ones meant to try to cook up some sort of distinctive signature style.
|
||||
|
||||
A signature style is the visual equivalent of what in show business is known as a "schtick": something that immediately identifies the work as yours and no one else's. For example, when you see a painting that looks like a certain kind of cartoon, you know it's by Roy Lichtenstein. So if you see a big painting of this type hanging in the apartment of a hedge fund manager, you know he paid millions of dollars for it. That's not always why artists have a signature style, but it's usually why buyers pay a lot for such work. [6]
|
||||
|
||||
There were plenty of earnest students too: kids who "could draw" in high school, and now had come to what was supposed to be the best art school in the country, to learn to draw even better. They tended to be confused and demoralized by what they found at RISD, but they kept going, because painting was what they did. I was not one of the kids who could draw in high school, but at RISD I was definitely closer to their tribe than the tribe of signature style seekers.
|
||||
|
||||
I learned a lot in the color class I took at RISD, but otherwise I was basically teaching myself to paint, and I could do that for free. So in 1993 I dropped out. I hung around Providence for a bit, and then my college friend Nancy Parmet did me a big favor. A rent-controlled apartment in a building her mother owned in New York was becoming vacant. Did I want it? It wasn't much more than my current place, and New York was supposed to be where the artists were. So yes, I wanted it! [7]
|
||||
|
||||
Asterix comics begin by zooming in on a tiny corner of Roman Gaul that turns out not to be controlled by the Romans. You can do something similar on a map of New York City: if you zoom in on the Upper East Side, there's a tiny corner that's not rich, or at least wasn't in 1993. It's called Yorkville, and that was my new home. Now I was a New York artist — in the strictly technical sense of making paintings and living in New York.
|
||||
|
||||
I was nervous about money, because I could sense that Interleaf was on the way down. Freelance Lisp hacking work was very rare, and I didn't want to have to program in another language, which in those days would have meant C++ if I was lucky. So with my unerring nose for financial opportunity, I decided to write another book on Lisp. This would be a popular book, the sort of book that could be used as a textbook. I imagined myself living frugally off the royalties and spending all my time painting. (The painting on the cover of this book, ANSI Common Lisp, is one that I painted around this time.)
|
||||
|
||||
The best thing about New York for me was the presence of Idelle and Julian Weber. Idelle Weber was a painter, one of the early photorealists, and I'd taken her painting class at Harvard. I've never known a teacher more beloved by her students. Large numbers of former students kept in touch with her, including me. After I moved to New York I became her de facto studio assistant.
|
||||
|
||||
She liked to paint on big, square canvases, 4 to 5 feet on a side. One day in late 1994 as I was stretching one of these monsters there was something on the radio about a famous fund manager. He wasn't that much older than me, and was super rich. The thought suddenly occurred to me: why don't I become rich? Then I'll be able to work on whatever I want.
|
||||
|
||||
Meanwhile I'd been hearing more and more about this new thing called the World Wide Web. Robert Morris showed it to me when I visited him in Cambridge, where he was now in grad school at Harvard. It seemed to me that the web would be a big deal. I'd seen what graphical user interfaces had done for the popularity of microcomputers. It seemed like the web would do the same for the internet.
|
||||
|
||||
If I wanted to get rich, here was the next train leaving the station. I was right about that part. What I got wrong was the idea. I decided we should start a company to put art galleries online. I can't honestly say, after reading so many Y Combinator applications, that this was the worst startup idea ever, but it was up there. Art galleries didn't want to be online, and still don't, not the fancy ones. That's not how they sell. I wrote some software to generate web sites for galleries, and Robert wrote some to resize images and set up an http server to serve the pages. Then we tried to sign up galleries. To call this a difficult sale would be an understatement. It was difficult to give away. A few galleries let us make sites for them for free, but none paid us.
|
||||
|
||||
Then some online stores started to appear, and I realized that except for the order buttons they were identical to the sites we'd been generating for galleries. This impressive-sounding thing called an "internet storefront" was something we already knew how to build.
|
||||
|
||||
So in the summer of 1995, after I submitted the camera-ready copy of ANSI Common Lisp to the publishers, we started trying to write software to build online stores. At first this was going to be normal desktop software, which in those days meant Windows software. That was an alarming prospect, because neither of us knew how to write Windows software or wanted to learn. We lived in the Unix world. But we decided we'd at least try writing a prototype store builder on Unix. Robert wrote a shopping cart, and I wrote a new site generator for stores — in Lisp, of course.
|
||||
|
||||
We were working out of Robert's apartment in Cambridge. His roommate was away for big chunks of time, during which I got to sleep in his room. For some reason there was no bed frame or sheets, just a mattress on the floor. One morning as I was lying on this mattress I had an idea that made me sit up like a capital L. What if we ran the software on the server, and let users control it by clicking on links? Then we'd never have to write anything to run on users' computers. We could generate the sites on the same server we'd serve them from. Users wouldn't need anything more than a browser.
|
||||
|
||||
This kind of software, known as a web app, is common now, but at the time it wasn't clear that it was even possible. To find out, we decided to try making a version of our store builder that you could control through the browser. A couple days later, on August 12, we had one that worked. The UI was horrible, but it proved you could build a whole store through the browser, without any client software or typing anything into the command line on the server.
|
||||
|
||||
Now we felt like we were really onto something. I had visions of a whole new generation of software working this way. You wouldn't need versions, or ports, or any of that crap. At Interleaf there had been a whole group called Release Engineering that seemed to be at least as big as the group that actually wrote the software. Now you could just update the software right on the server.
|
||||
|
||||
We started a new company we called Viaweb, after the fact that our software worked via the web, and we got $10,000 in seed funding from Idelle's husband Julian. In return for that and doing the initial legal work and giving us business advice, we gave him 10% of the company. Ten years later this deal became the model for Y Combinator's. We knew founders needed something like this, because we'd needed it ourselves.
|
||||
|
||||
At this stage I had a negative net worth, because the thousand dollars or so I had in the bank was more than counterbalanced by what I owed the government in taxes. (Had I diligently set aside the proper proportion of the money I'd made consulting for Interleaf? No, I had not.) So although Robert had his graduate student stipend, I needed that seed funding to live on.
|
||||
|
||||
We originally hoped to launch in September, but we got more ambitious about the software as we worked on it. Eventually we managed to build a WYSIWYG site builder, in the sense that as you were creating pages, they looked exactly like the static ones that would be generated later, except that instead of leading to static pages, the links all referred to closures stored in a hash table on the server.
|
||||
|
||||
It helped to have studied art, because the main goal of an online store builder is to make users look legit, and the key to looking legit is high production values. If you get page layouts and fonts and colors right, you can make a guy running a store out of his bedroom look more legit than a big company.
|
||||
|
||||
(If you're curious why my site looks so old-fashioned, it's because it's still made with this software. It may look clunky today, but in 1996 it was the last word in slick.)
|
||||
|
||||
In September, Robert rebelled. "We've been working on this for a month," he said, "and it's still not done." This is funny in retrospect, because he would still be working on it almost 3 years later. But I decided it might be prudent to recruit more programmers, and I asked Robert who else in grad school with him was really good. He recommended Trevor Blackwell, which surprised me at first, because at that point I knew Trevor mainly for his plan to reduce everything in his life to a stack of notecards, which he carried around with him. But Rtm was right, as usual. Trevor turned out to be a frighteningly effective hacker.
|
||||
|
||||
It was a lot of fun working with Robert and Trevor. They're the two most independent-minded people I know, and in completely different ways. If you could see inside Rtm's brain it would look like a colonial New England church, and if you could see inside Trevor's it would look like the worst excesses of Austrian Rococo.
|
||||
|
||||
We opened for business, with 6 stores, in January 1996. It was just as well we waited a few months, because although we worried we were late, we were actually almost fatally early. There was a lot of talk in the press then about ecommerce, but not many people actually wanted online stores. [8]
|
||||
|
||||
There were three main parts to the software: the editor, which people used to build sites and which I wrote, the shopping cart, which Robert wrote, and the manager, which kept track of orders and statistics, and which Trevor wrote. In its time, the editor was one of the best general-purpose site builders. I kept the code tight and didn't have to integrate with any other software except Robert's and Trevor's, so it was quite fun to work on. If all I'd had to do was work on this software, the next 3 years would have been the easiest of my life. Unfortunately I had to do a lot more, all of it stuff I was worse at than programming, and the next 3 years were instead the most stressful.
|
||||
|
||||
There were a lot of startups making ecommerce software in the second half of the 90s. We were determined to be the Microsoft Word, not the Interleaf. Which meant being easy to use and inexpensive. It was lucky for us that we were poor, because that caused us to make Viaweb even more inexpensive than we realized. We charged $100 a month for a small store and $300 a month for a big one. This low price was a big attraction, and a constant thorn in the sides of competitors, but it wasn't because of some clever insight that we set the price low. We had no idea what businesses paid for things. $300 a month seemed like a lot of money to us.
|
||||
|
||||
We did a lot of things right by accident like that. For example, we did what's now called "doing things that don't scale," although at the time we would have described it as "being so lame that we're driven to the most desperate measures to get users." The most common of which was building stores for them. This seemed particularly humiliating, since the whole raison d'etre of our software was that people could use it to make their own stores. But anything to get users.
|
||||
|
||||
We learned a lot more about retail than we wanted to know. For example, that if you could only have a small image of a man's shirt (and all images were small then by present standards), it was better to have a closeup of the collar than a picture of the whole shirt. The reason I remember learning this was that it meant I had to rescan about 30 images of men's shirts. My first set of scans were so beautiful too.
|
||||
|
||||
Though this felt wrong, it was exactly the right thing to be doing. Building stores for users taught us about retail, and about how it felt to use our software. I was initially both mystified and repelled by "business" and thought we needed a "business person" to be in charge of it, but once we started to get users, I was converted, in much the same way I was converted to fatherhood once I had kids. Whatever users wanted, I was all theirs. Maybe one day we'd have so many users that I couldn't scan their images for them, but in the meantime there was nothing more important to do.
|
||||
|
||||
Another thing I didn't get at the time is that growth rate is the ultimate test of a startup. Our growth rate was fine. We had about 70 stores at the end of 1996 and about 500 at the end of 1997. I mistakenly thought the thing that mattered was the absolute number of users. And that is the thing that matters in the sense that that's how much money you're making, and if you're not making enough, you might go out of business. But in the long term the growth rate takes care of the absolute number. If we'd been a startup I was advising at Y Combinator, I would have said: Stop being so stressed out, because you're doing fine. You're growing 7x a year. Just don't hire too many more people and you'll soon be profitable, and then you'll control your own destiny.
|
||||
|
||||
Alas I hired lots more people, partly because our investors wanted me to, and partly because that's what startups did during the Internet Bubble. A company with just a handful of employees would have seemed amateurish. So we didn't reach breakeven until about when Yahoo bought us in the summer of 1998. Which in turn meant we were at the mercy of investors for the entire life of the company. And since both we and our investors were noobs at startups, the result was a mess even by startup standards.
|
||||
|
||||
It was a huge relief when Yahoo bought us. In principle our Viaweb stock was valuable. It was a share in a business that was profitable and growing rapidly. But it didn't feel very valuable to me; I had no idea how to value a business, but I was all too keenly aware of the near-death experiences we seemed to have every few months. Nor had I changed my grad student lifestyle significantly since we started. So when Yahoo bought us it felt like going from rags to riches. Since we were going to California, I bought a car, a yellow 1998 VW GTI. I remember thinking that its leather seats alone were by far the most luxurious thing I owned.
|
||||
|
||||
The next year, from the summer of 1998 to the summer of 1999, must have been the least productive of my life. I didn't realize it at the time, but I was worn out from the effort and stress of running Viaweb. For a while after I got to California I tried to continue my usual m.o. of programming till 3 in the morning, but fatigue combined with Yahoo's prematurely aged culture and grim cube farm in Santa Clara gradually dragged me down. After a few months it felt disconcertingly like working at Interleaf.
|
||||
|
||||
Yahoo had given us a lot of options when they bought us. At the time I thought Yahoo was so overvalued that they'd never be worth anything, but to my astonishment the stock went up 5x in the next year. I hung on till the first chunk of options vested, then in the summer of 1999 I left. It had been so long since I'd painted anything that I'd half forgotten why I was doing this. My brain had been entirely full of software and men's shirts for 4 years. But I had done this to get rich so I could paint, I reminded myself, and now I was rich, so I should go paint.
|
||||
|
||||
When I said I was leaving, my boss at Yahoo had a long conversation with me about my plans. I told him all about the kinds of pictures I wanted to paint. At the time I was touched that he took such an interest in me. Now I realize it was because he thought I was lying. My options at that point were worth about $2 million a month. If I was leaving that kind of money on the table, it could only be to go and start some new startup, and if I did, I might take people with me. This was the height of the Internet Bubble, and Yahoo was ground zero of it. My boss was at that moment a billionaire. Leaving then to start a new startup must have seemed to him an insanely, and yet also plausibly, ambitious plan.
|
||||
|
||||
But I really was quitting to paint, and I started immediately. There was no time to lose. I'd already burned 4 years getting rich. Now when I talk to founders who are leaving after selling their companies, my advice is always the same: take a vacation. That's what I should have done, just gone off somewhere and done nothing for a month or two, but the idea never occurred to me.
|
||||
|
||||
So I tried to paint, but I just didn't seem to have any energy or ambition. Part of the problem was that I didn't know many people in California. I'd compounded this problem by buying a house up in the Santa Cruz Mountains, with a beautiful view but miles from anywhere. I stuck it out for a few more months, then in desperation I went back to New York, where unless you understand about rent control you'll be surprised to hear I still had my apartment, sealed up like a tomb of my old life. Idelle was in New York at least, and there were other people trying to paint there, even though I didn't know any of them.
|
||||
|
||||
When I got back to New York I resumed my old life, except now I was rich. It was as weird as it sounds. I resumed all my old patterns, except now there were doors where there hadn't been. Now when I was tired of walking, all I had to do was raise my hand, and (unless it was raining) a taxi would stop to pick me up. Now when I walked past charming little restaurants I could go in and order lunch. It was exciting for a while. Painting started to go better. I experimented with a new kind of still life where I'd paint one painting in the old way, then photograph it and print it, blown up, on canvas, and then use that as the underpainting for a second still life, painted from the same objects (which hopefully hadn't rotted yet).
|
||||
|
||||
Meanwhile I looked for an apartment to buy. Now I could actually choose what neighborhood to live in. Where, I asked myself and various real estate agents, is the Cambridge of New York? Aided by occasional visits to actual Cambridge, I gradually realized there wasn't one. Huh.
|
||||
|
||||
Around this time, in the spring of 2000, I had an idea. It was clear from our experience with Viaweb that web apps were the future. Why not build a web app for making web apps? Why not let people edit code on our server through the browser, and then host the resulting applications for them? [9] You could run all sorts of services on the servers that these applications could use just by making an API call: making and receiving phone calls, manipulating images, taking credit card payments, etc.
|
||||
|
||||
I got so excited about this idea that I couldn't think about anything else. It seemed obvious that this was the future. I didn't particularly want to start another company, but it was clear that this idea would have to be embodied as one, so I decided to move to Cambridge and start it. I hoped to lure Robert into working on it with me, but there I ran into a hitch. Robert was now a postdoc at MIT, and though he'd made a lot of money the last time I'd lured him into working on one of my schemes, it had also been a huge time sink. So while he agreed that it sounded like a plausible idea, he firmly refused to work on it.
|
||||
|
||||
Hmph. Well, I'd do it myself then. I recruited Dan Giffin, who had worked for Viaweb, and two undergrads who wanted summer jobs, and we got to work trying to build what it's now clear is about twenty companies and several open source projects worth of software. The language for defining applications would of course be a dialect of Lisp. But I wasn't so naive as to assume I could spring an overt Lisp on a general audience; we'd hide the parentheses, like Dylan did.
|
||||
|
||||
By then there was a name for the kind of company Viaweb was, an "application service provider," or ASP. This name didn't last long before it was replaced by "software as a service," but it was current for long enough that I named this new company after it: it was going to be called Aspra.
|
||||
|
||||
I started working on the application builder, Dan worked on network infrastructure, and the two undergrads worked on the first two services (images and phone calls). But about halfway through the summer I realized I really didn't want to run a company — especially not a big one, which it was looking like this would have to be. I'd only started Viaweb because I needed the money. Now that I didn't need money anymore, why was I doing this? If this vision had to be realized as a company, then screw the vision. I'd build a subset that could be done as an open source project.
|
||||
|
||||
Much to my surprise, the time I spent working on this stuff was not wasted after all. After we started Y Combinator, I would often encounter startups working on parts of this new architecture, and it was very useful to have spent so much time thinking about it and even trying to write some of it.
|
||||
|
||||
The subset I would build as an open source project was the new Lisp, whose parentheses I now wouldn't even have to hide. A lot of Lisp hackers dream of building a new Lisp, partly because one of the distinctive features of the language is that it has dialects, and partly, I think, because we have in our minds a Platonic form of Lisp that all existing dialects fall short of. I certainly did. So at the end of the summer Dan and I switched to working on this new dialect of Lisp, which I called Arc, in a house I bought in Cambridge.
|
||||
|
||||
The following spring, lightning struck. I was invited to give a talk at a Lisp conference, so I gave one about how we'd used Lisp at Viaweb. Afterward I put a postscript file of this talk online, on paulgraham.com, which I'd created years before using Viaweb but had never used for anything. In one day it got 30,000 page views. What on earth had happened? The referring urls showed that someone had posted it on Slashdot. [10]
|
||||
|
||||
Wow, I thought, there's an audience. If I write something and put it on the web, anyone can read it. That may seem obvious now, but it was surprising then. In the print era there was a narrow channel to readers, guarded by fierce monsters known as editors. The only way to get an audience for anything you wrote was to get it published as a book, or in a newspaper or magazine. Now anyone could publish anything.
|
||||
|
||||
This had been possible in principle since 1993, but not many people had realized it yet. I had been intimately involved with building the infrastructure of the web for most of that time, and a writer as well, and it had taken me 8 years to realize it. Even then it took me several years to understand the implications. It meant there would be a whole new generation of essays. [11]
|
||||
|
||||
In the print era, the channel for publishing essays had been vanishingly small. Except for a few officially anointed thinkers who went to the right parties in New York, the only people allowed to publish essays were specialists writing about their specialties. There were so many essays that had never been written, because there had been no way to publish them. Now they could be, and I was going to write them. [12]
|
||||
|
||||
I've worked on several different things, but to the extent there was a turning point where I figured out what to work on, it was when I started publishing essays online. From then on I knew that whatever else I did, I'd always write essays too.
|
||||
|
||||
I knew that online essays would be a marginal medium at first. Socially they'd seem more like rants posted by nutjobs on their GeoCities sites than the genteel and beautifully typeset compositions published in The New Yorker. But by this point I knew enough to find that encouraging instead of discouraging.
|
||||
|
||||
One of the most conspicuous patterns I've noticed in my life is how well it has worked, for me at least, to work on things that weren't prestigious. Still life has always been the least prestigious form of painting. Viaweb and Y Combinator both seemed lame when we started them. I still get the glassy eye from strangers when they ask what I'm writing, and I explain that it's an essay I'm going to publish on my web site. Even Lisp, though prestigious intellectually in something like the way Latin is, also seems about as hip.
|
||||
|
||||
It's not that unprestigious types of work are good per se. But when you find yourself drawn to some kind of work despite its current lack of prestige, it's a sign both that there's something real to be discovered there, and that you have the right kind of motives. Impure motives are a big danger for the ambitious. If anything is going to lead you astray, it will be the desire to impress people. So while working on things that aren't prestigious doesn't guarantee you're on the right track, it at least guarantees you're not on the most common type of wrong one.
|
||||
|
||||
Over the next several years I wrote lots of essays about all kinds of different topics. O'Reilly reprinted a collection of them as a book, called Hackers & Painters after one of the essays in it. I also worked on spam filters, and did some more painting. I used to have dinners for a group of friends every thursday night, which taught me how to cook for groups. And I bought another building in Cambridge, a former candy factory (and later, twas said, porn studio), to use as an office.
|
||||
|
||||
One night in October 2003 there was a big party at my house. It was a clever idea of my friend Maria Daniels, who was one of the thursday diners. Three separate hosts would all invite their friends to one party. So for every guest, two thirds of the other guests would be people they didn't know but would probably like. One of the guests was someone I didn't know but would turn out to like a lot: a woman called Jessica Livingston. A couple days later I asked her out.
|
||||
|
||||
Jessica was in charge of marketing at a Boston investment bank. This bank thought it understood startups, but over the next year, as she met friends of mine from the startup world, she was surprised how different reality was. And how colorful their stories were. So she decided to compile a book of interviews with startup founders.
|
||||
|
||||
When the bank had financial problems and she had to fire half her staff, she started looking for a new job. In early 2005 she interviewed for a marketing job at a Boston VC firm. It took them weeks to make up their minds, and during this time I started telling her about all the things that needed to be fixed about venture capital. They should make a larger number of smaller investments instead of a handful of giant ones, they should be funding younger, more technical founders instead of MBAs, they should let the founders remain as CEO, and so on.
|
||||
|
||||
One of my tricks for writing essays had always been to give talks. The prospect of having to stand up in front of a group of people and tell them something that won't waste their time is a great spur to the imagination. When the Harvard Computer Society, the undergrad computer club, asked me to give a talk, I decided I would tell them how to start a startup. Maybe they'd be able to avoid the worst of the mistakes we'd made.
|
||||
|
||||
So I gave this talk, in the course of which I told them that the best sources of seed funding were successful startup founders, because then they'd be sources of advice too. Whereupon it seemed they were all looking expectantly at me. Horrified at the prospect of having my inbox flooded by business plans (if I'd only known), I blurted out "But not me!" and went on with the talk. But afterward it occurred to me that I should really stop procrastinating about angel investing. I'd been meaning to since Yahoo bought us, and now it was 7 years later and I still hadn't done one angel investment.
|
||||
|
||||
Meanwhile I had been scheming with Robert and Trevor about projects we could work on together. I missed working with them, and it seemed like there had to be something we could collaborate on.
|
||||
|
||||
As Jessica and I were walking home from dinner on March 11, at the corner of Garden and Walker streets, these three threads converged. Screw the VCs who were taking so long to make up their minds. We'd start our own investment firm and actually implement the ideas we'd been talking about. I'd fund it, and Jessica could quit her job and work for it, and we'd get Robert and Trevor as partners too. [13]
|
||||
|
||||
Once again, ignorance worked in our favor. We had no idea how to be angel investors, and in Boston in 2005 there were no Ron Conways to learn from. So we just made what seemed like the obvious choices, and some of the things we did turned out to be novel.
|
||||
|
||||
There are multiple components to Y Combinator, and we didn't figure them all out at once. The part we got first was to be an angel firm. In those days, those two words didn't go together. There were VC firms, which were organized companies with people whose job it was to make investments, but they only did big, million dollar investments. And there were angels, who did smaller investments, but these were individuals who were usually focused on other things and made investments on the side. And neither of them helped founders enough in the beginning. We knew how helpless founders were in some respects, because we remembered how helpless we'd been. For example, one thing Julian had done for us that seemed to us like magic was to get us set up as a company. We were fine writing fairly difficult software, but actually getting incorporated, with bylaws and stock and all that stuff, how on earth did you do that? Our plan was not only to make seed investments, but to do for startups everything Julian had done for us.
|
||||
|
||||
YC was not organized as a fund. It was cheap enough to run that we funded it with our own money. That went right by 99% of readers, but professional investors are thinking "Wow, that means they got all the returns." But once again, this was not due to any particular insight on our part. We didn't know how VC firms were organized. It never occurred to us to try to raise a fund, and if it had, we wouldn't have known where to start. [14]
|
||||
|
||||
The most distinctive thing about YC is the batch model: to fund a bunch of startups all at once, twice a year, and then to spend three months focusing intensively on trying to help them. That part we discovered by accident, not merely implicitly but explicitly due to our ignorance about investing. We needed to get experience as investors. What better way, we thought, than to fund a whole bunch of startups at once? We knew undergrads got temporary jobs at tech companies during the summer. Why not organize a summer program where they'd start startups instead? We wouldn't feel guilty for being in a sense fake investors, because they would in a similar sense be fake founders. So while we probably wouldn't make much money out of it, we'd at least get to practice being investors on them, and they for their part would probably have a more interesting summer than they would working at Microsoft.
|
||||
|
||||
We'd use the building I owned in Cambridge as our headquarters. We'd all have dinner there once a week — on tuesdays, since I was already cooking for the thursday diners on thursdays — and after dinner we'd bring in experts on startups to give talks.
|
||||
|
||||
We knew undergrads were deciding then about summer jobs, so in a matter of days we cooked up something we called the Summer Founders Program, and I posted an announcement on my site, inviting undergrads to apply. I had never imagined that writing essays would be a way to get "deal flow," as investors call it, but it turned out to be the perfect source. [15] We got 225 applications for the Summer Founders Program, and we were surprised to find that a lot of them were from people who'd already graduated, or were about to that spring. Already this SFP thing was starting to feel more serious than we'd intended.
|
||||
|
||||
We invited about 20 of the 225 groups to interview in person, and from those we picked 8 to fund. They were an impressive group. That first batch included reddit, Justin Kan and Emmett Shear, who went on to found Twitch, Aaron Swartz, who had already helped write the RSS spec and would a few years later become a martyr for open access, and Sam Altman, who would later become the second president of YC. I don't think it was entirely luck that the first batch was so good. You had to be pretty bold to sign up for a weird thing like the Summer Founders Program instead of a summer job at a legit place like Microsoft or Goldman Sachs.
|
||||
|
||||
The deal for startups was based on a combination of the deal we did with Julian ($10k for 10%) and what Robert said MIT grad students got for the summer ($6k). We invested $6k per founder, which in the typical two-founder case was $12k, in return for 6%. That had to be fair, because it was twice as good as the deal we ourselves had taken. Plus that first summer, which was really hot, Jessica brought the founders free air conditioners. [16]
|
||||
|
||||
Fairly quickly I realized that we had stumbled upon the way to scale startup funding. Funding startups in batches was more convenient for us, because it meant we could do things for a lot of startups at once, but being part of a batch was better for the startups too. It solved one of the biggest problems faced by founders: the isolation. Now you not only had colleagues, but colleagues who understood the problems you were facing and could tell you how they were solving them.
|
||||
|
||||
As YC grew, we started to notice other advantages of scale. The alumni became a tight community, dedicated to helping one another, and especially the current batch, whose shoes they remembered being in. We also noticed that the startups were becoming one another's customers. We used to refer jokingly to the "YC GDP," but as YC grows this becomes less and less of a joke. Now lots of startups get their initial set of customers almost entirely from among their batchmates.
|
||||
|
||||
I had not originally intended YC to be a full-time job. I was going to do three things: hack, write essays, and work on YC. As YC grew, and I grew more excited about it, it started to take up a lot more than a third of my attention. But for the first few years I was still able to work on other things.
|
||||
|
||||
In the summer of 2006, Robert and I started working on a new version of Arc. This one was reasonably fast, because it was compiled into Scheme. To test this new Arc, I wrote Hacker News in it. It was originally meant to be a news aggregator for startup founders and was called Startup News, but after a few months I got tired of reading about nothing but startups. Plus it wasn't startup founders we wanted to reach. It was future startup founders. So I changed the name to Hacker News and the topic to whatever engaged one's intellectual curiosity.
|
||||
|
||||
HN was no doubt good for YC, but it was also by far the biggest source of stress for me. If all I'd had to do was select and help founders, life would have been so easy. And that implies that HN was a mistake. Surely the biggest source of stress in one's work should at least be something close to the core of the work. Whereas I was like someone who was in pain while running a marathon not from the exertion of running, but because I had a blister from an ill-fitting shoe. When I was dealing with some urgent problem during YC, there was about a 60% chance it had to do with HN, and a 40% chance it had do with everything else combined. [17]
|
||||
|
||||
As well as HN, I wrote all of YC's internal software in Arc. But while I continued to work a good deal in Arc, I gradually stopped working on Arc, partly because I didn't have time to, and partly because it was a lot less attractive to mess around with the language now that we had all this infrastructure depending on it. So now my three projects were reduced to two: writing essays and working on YC.
|
||||
|
||||
YC was different from other kinds of work I've done. Instead of deciding for myself what to work on, the problems came to me. Every 6 months there was a new batch of startups, and their problems, whatever they were, became our problems. It was very engaging work, because their problems were quite varied, and the good founders were very effective. If you were trying to learn the most you could about startups in the shortest possible time, you couldn't have picked a better way to do it.
|
||||
|
||||
There were parts of the job I didn't like. Disputes between cofounders, figuring out when people were lying to us, fighting with people who maltreated the startups, and so on. But I worked hard even at the parts I didn't like. I was haunted by something Kevin Hale once said about companies: "No one works harder than the boss." He meant it both descriptively and prescriptively, and it was the second part that scared me. I wanted YC to be good, so if how hard I worked set the upper bound on how hard everyone else worked, I'd better work very hard.
|
||||
|
||||
One day in 2010, when he was visiting California for interviews, Robert Morris did something astonishing: he offered me unsolicited advice. I can only remember him doing that once before. One day at Viaweb, when I was bent over double from a kidney stone, he suggested that it would be a good idea for him to take me to the hospital. That was what it took for Rtm to offer unsolicited advice. So I remember his exact words very clearly. "You know," he said, "you should make sure Y Combinator isn't the last cool thing you do."
|
||||
|
||||
At the time I didn't understand what he meant, but gradually it dawned on me that he was saying I should quit. This seemed strange advice, because YC was doing great. But if there was one thing rarer than Rtm offering advice, it was Rtm being wrong. So this set me thinking. It was true that on my current trajectory, YC would be the last thing I did, because it was only taking up more of my attention. It had already eaten Arc, and was in the process of eating essays too. Either YC was my life's work or I'd have to leave eventually. And it wasn't, so I would.
|
||||
|
||||
In the summer of 2012 my mother had a stroke, and the cause turned out to be a blood clot caused by colon cancer. The stroke destroyed her balance, and she was put in a nursing home, but she really wanted to get out of it and back to her house, and my sister and I were determined to help her do it. I used to fly up to Oregon to visit her regularly, and I had a lot of time to think on those flights. On one of them I realized I was ready to hand YC over to someone else.
|
||||
|
||||
I asked Jessica if she wanted to be president, but she didn't, so we decided we'd try to recruit Sam Altman. We talked to Robert and Trevor and we agreed to make it a complete changing of the guard. Up till that point YC had been controlled by the original LLC we four had started. But we wanted YC to last for a long time, and to do that it couldn't be controlled by the founders. So if Sam said yes, we'd let him reorganize YC. Robert and I would retire, and Jessica and Trevor would become ordinary partners.
|
||||
|
||||
When we asked Sam if he wanted to be president of YC, initially he said no. He wanted to start a startup to make nuclear reactors. But I kept at it, and in October 2013 he finally agreed. We decided he'd take over starting with the winter 2014 batch. For the rest of 2013 I left running YC more and more to Sam, partly so he could learn the job, and partly because I was focused on my mother, whose cancer had returned.
|
||||
|
||||
She died on January 15, 2014. We knew this was coming, but it was still hard when it did.
|
||||
|
||||
I kept working on YC till March, to help get that batch of startups through Demo Day, then I checked out pretty completely. (I still talk to alumni and to new startups working on things I'm interested in, but that only takes a few hours a week.)
|
||||
|
||||
What should I do next? Rtm's advice hadn't included anything about that. I wanted to do something completely different, so I decided I'd paint. I wanted to see how good I could get if I really focused on it. So the day after I stopped working on YC, I started painting. I was rusty and it took a while to get back into shape, but it was at least completely engaging. [18]
|
||||
|
||||
I spent most of the rest of 2014 painting. I'd never been able to work so uninterruptedly before, and I got to be better than I had been. Not good enough, but better. Then in November, right in the middle of a painting, I ran out of steam. Up till that point I'd always been curious to see how the painting I was working on would turn out, but suddenly finishing this one seemed like a chore. So I stopped working on it and cleaned my brushes and haven't painted since. So far anyway.
|
||||
|
||||
I realize that sounds rather wimpy. But attention is a zero sum game. If you can choose what to work on, and you choose a project that's not the best one (or at least a good one) for you, then it's getting in the way of another project that is. And at 50 there was some opportunity cost to screwing around.
|
||||
|
||||
I started writing essays again, and wrote a bunch of new ones over the next few months. I even wrote a couple that weren't about startups. Then in March 2015 I started working on Lisp again.
|
||||
|
||||
The distinctive thing about Lisp is that its core is a language defined by writing an interpreter in itself. It wasn't originally intended as a programming language in the ordinary sense. It was meant to be a formal model of computation, an alternative to the Turing machine. If you want to write an interpreter for a language in itself, what's the minimum set of predefined operators you need? The Lisp that John McCarthy invented, or more accurately discovered, is an answer to that question. [19]
|
||||
|
||||
McCarthy didn't realize this Lisp could even be used to program computers till his grad student Steve Russell suggested it. Russell translated McCarthy's interpreter into IBM 704 machine language, and from that point Lisp started also to be a programming language in the ordinary sense. But its origins as a model of computation gave it a power and elegance that other languages couldn't match. It was this that attracted me in college, though I didn't understand why at the time.
|
||||
|
||||
McCarthy's 1960 Lisp did nothing more than interpret Lisp expressions. It was missing a lot of things you'd want in a programming language. So these had to be added, and when they were, they weren't defined using McCarthy's original axiomatic approach. That wouldn't have been feasible at the time. McCarthy tested his interpreter by hand-simulating the execution of programs. But it was already getting close to the limit of interpreters you could test that way — indeed, there was a bug in it that McCarthy had overlooked. To test a more complicated interpreter, you'd have had to run it, and computers then weren't powerful enough.
|
||||
|
||||
Now they are, though. Now you could continue using McCarthy's axiomatic approach till you'd defined a complete programming language. And as long as every change you made to McCarthy's Lisp was a discoveredness-preserving transformation, you could, in principle, end up with a complete language that had this quality. Harder to do than to talk about, of course, but if it was possible in principle, why not try? So I decided to take a shot at it. It took 4 years, from March 26, 2015 to October 12, 2019. It was fortunate that I had a precisely defined goal, or it would have been hard to keep at it for so long.
|
||||
|
||||
I wrote this new Lisp, called Bel, in itself in Arc. That may sound like a contradiction, but it's an indication of the sort of trickery I had to engage in to make this work. By means of an egregious collection of hacks I managed to make something close enough to an interpreter written in itself that could actually run. Not fast, but fast enough to test.
|
||||
|
||||
I had to ban myself from writing essays during most of this time, or I'd never have finished. In late 2015 I spent 3 months writing essays, and when I went back to working on Bel I could barely understand the code. Not so much because it was badly written as because the problem is so convoluted. When you're working on an interpreter written in itself, it's hard to keep track of what's happening at what level, and errors can be practically encrypted by the time you get them.
|
||||
|
||||
So I said no more essays till Bel was done. But I told few people about Bel while I was working on it. So for years it must have seemed that I was doing nothing, when in fact I was working harder than I'd ever worked on anything. Occasionally after wrestling for hours with some gruesome bug I'd check Twitter or HN and see someone asking "Does Paul Graham still code?"
|
||||
|
||||
Working on Bel was hard but satisfying. I worked on it so intensively that at any given time I had a decent chunk of the code in my head and could write more there. I remember taking the boys to the coast on a sunny day in 2015 and figuring out how to deal with some problem involving continuations while I watched them play in the tide pools. It felt like I was doing life right. I remember that because I was slightly dismayed at how novel it felt. The good news is that I had more moments like this over the next few years.
|
||||
|
||||
In the summer of 2016 we moved to England. We wanted our kids to see what it was like living in another country, and since I was a British citizen by birth, that seemed the obvious choice. We only meant to stay for a year, but we liked it so much that we still live there. So most of Bel was written in England.
|
||||
|
||||
In the fall of 2019, Bel was finally finished. Like McCarthy's original Lisp, it's a spec rather than an implementation, although like McCarthy's Lisp it's a spec expressed as code.
|
||||
|
||||
Now that I could write essays again, I wrote a bunch about topics I'd had stacked up. I kept writing essays through 2020, but I also started to think about other things I could work on. How should I choose what to do? Well, how had I chosen what to work on in the past? I wrote an essay for myself to answer that question, and I was surprised how long and messy the answer turned out to be. If this surprised me, who'd lived it, then I thought perhaps it would be interesting to other people, and encouraging to those with similarly messy lives. So I wrote a more detailed version for others to read, and this is the last sentence of it.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Notes
|
||||
|
||||
[1] My experience skipped a step in the evolution of computers: time-sharing machines with interactive OSes. I went straight from batch processing to microcomputers, which made microcomputers seem all the more exciting.
|
||||
|
||||
[2] Italian words for abstract concepts can nearly always be predicted from their English cognates (except for occasional traps like polluzione). It's the everyday words that differ. So if you string together a lot of abstract concepts with a few simple verbs, you can make a little Italian go a long way.
|
||||
|
||||
[3] I lived at Piazza San Felice 4, so my walk to the Accademia went straight down the spine of old Florence: past the Pitti, across the bridge, past Orsanmichele, between the Duomo and the Baptistery, and then up Via Ricasoli to Piazza San Marco. I saw Florence at street level in every possible condition, from empty dark winter evenings to sweltering summer days when the streets were packed with tourists.
|
||||
|
||||
[4] You can of course paint people like still lives if you want to, and they're willing. That sort of portrait is arguably the apex of still life painting, though the long sitting does tend to produce pained expressions in the sitters.
|
||||
|
||||
[5] Interleaf was one of many companies that had smart people and built impressive technology, and yet got crushed by Moore's Law. In the 1990s the exponential growth in the power of commodity (i.e. Intel) processors rolled up high-end, special-purpose hardware and software companies like a bulldozer.
|
||||
|
||||
[6] The signature style seekers at RISD weren't specifically mercenary. In the art world, money and coolness are tightly coupled. Anything expensive comes to be seen as cool, and anything seen as cool will soon become equally expensive.
|
||||
|
||||
[7] Technically the apartment wasn't rent-controlled but rent-stabilized, but this is a refinement only New Yorkers would know or care about. The point is that it was really cheap, less than half market price.
|
||||
|
||||
[8] Most software you can launch as soon as it's done. But when the software is an online store builder and you're hosting the stores, if you don't have any users yet, that fact will be painfully obvious. So before we could launch publicly we had to launch privately, in the sense of recruiting an initial set of users and making sure they had decent-looking stores.
|
||||
|
||||
[9] We'd had a code editor in Viaweb for users to define their own page styles. They didn't know it, but they were editing Lisp expressions underneath. But this wasn't an app editor, because the code ran when the merchants' sites were generated, not when shoppers visited them.
|
||||
|
||||
[10] This was the first instance of what is now a familiar experience, and so was what happened next, when I read the comments and found they were full of angry people. How could I claim that Lisp was better than other languages? Weren't they all Turing complete? People who see the responses to essays I write sometimes tell me how sorry they feel for me, but I'm not exaggerating when I reply that it has always been like this, since the very beginning. It comes with the territory. An essay must tell readers things they don't already know, and some people dislike being told such things.
|
||||
|
||||
[11] People put plenty of stuff on the internet in the 90s of course, but putting something online is not the same as publishing it online. Publishing online means you treat the online version as the (or at least a) primary version.
|
||||
|
||||
[12] There is a general lesson here that our experience with Y Combinator also teaches: Customs continue to constrain you long after the restrictions that caused them have disappeared. Customary VC practice had once, like the customs about publishing essays, been based on real constraints. Startups had once been much more expensive to start, and proportionally rare. Now they could be cheap and common, but the VCs' customs still reflected the old world, just as customs about writing essays still reflected the constraints of the print era.
|
||||
|
||||
Which in turn implies that people who are independent-minded (i.e. less influenced by custom) will have an advantage in fields affected by rapid change (where customs are more likely to be obsolete).
|
||||
|
||||
Here's an interesting point, though: you can't always predict which fields will be affected by rapid change. Obviously software and venture capital will be, but who would have predicted that essay writing would be?
|
||||
|
||||
[13] Y Combinator was not the original name. At first we were called Cambridge Seed. But we didn't want a regional name, in case someone copied us in Silicon Valley, so we renamed ourselves after one of the coolest tricks in the lambda calculus, the Y combinator.
|
||||
|
||||
I picked orange as our color partly because it's the warmest, and partly because no VC used it. In 2005 all the VCs used staid colors like maroon, navy blue, and forest green, because they were trying to appeal to LPs, not founders. The YC logo itself is an inside joke: the Viaweb logo had been a white V on a red circle, so I made the YC logo a white Y on an orange square.
|
||||
|
||||
[14] YC did become a fund for a couple years starting in 2009, because it was getting so big I could no longer afford to fund it personally. But after Heroku got bought we had enough money to go back to being self-funded.
|
||||
|
||||
[15] I've never liked the term "deal flow," because it implies that the number of new startups at any given time is fixed. This is not only false, but it's the purpose of YC to falsify it, by causing startups to be founded that would not otherwise have existed.
|
||||
|
||||
[16] She reports that they were all different shapes and sizes, because there was a run on air conditioners and she had to get whatever she could, but that they were all heavier than she could carry now.
|
||||
|
||||
[17] Another problem with HN was a bizarre edge case that occurs when you both write essays and run a forum. When you run a forum, you're assumed to see if not every conversation, at least every conversation involving you. And when you write essays, people post highly imaginative misinterpretations of them on forums. Individually these two phenomena are tedious but bearable, but the combination is disastrous. You actually have to respond to the misinterpretations, because the assumption that you're present in the conversation means that not responding to any sufficiently upvoted misinterpretation reads as a tacit admission that it's correct. But that in turn encourages more; anyone who wants to pick a fight with you senses that now is their chance.
|
||||
|
||||
[18] The worst thing about leaving YC was not working with Jessica anymore. We'd been working on YC almost the whole time we'd known each other, and we'd neither tried nor wanted to separate it from our personal lives, so leaving was like pulling up a deeply rooted tree.
|
||||
|
||||
[19] One way to get more precise about the concept of invented vs discovered is to talk about space aliens. Any sufficiently advanced alien civilization would certainly know about the Pythagorean theorem, for example. I believe, though with less certainty, that they would also know about the Lisp in McCarthy's 1960 paper.
|
||||
|
||||
But if so there's no reason to suppose that this is the limit of the language that might be known to them. Presumably aliens need numbers and errors and I/O too. So it seems likely there exists at least one path out of McCarthy's Lisp along which discoveredness is preserved.
|
||||
|
||||
|
||||
|
||||
Thanks to Trevor Blackwell, John Collison, Patrick Collison, Daniel Gackle, Ralph Hazell, Jessica Livingston, Robert Morris, and Harj Taggar for reading drafts of this.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4f3b89c3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/supabase/supabase/blob/master/examples/ai/llamaindex/llamaindex.ipynb)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "2a1f181d-feeb-4b29-aabc-67a75234b92c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Supabase + LlamaIndex\n",
|
||||
"\n",
|
||||
"In this example we'll use PostgreSQL + pgvectors with [LlamaIndex's Supabase Vector Store](https://gpt-index.readthedocs.io/en/latest/examples/vector_stores/SupabaseVectorIndexDemo.html#setup-openai).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "3cab93f5-10d0-47c5-9f4e-64921461e7e2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Install Dependencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "a41bc3e4-ea52-43aa-9239-a431b49f029e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -qU vecs datasets llama_index html2text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0026437c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"# Uncomment to see debug logs\n",
|
||||
"# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)\n",
|
||||
"# logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))\n",
|
||||
"\n",
|
||||
"from llama_index import SimpleWebPageReader, StorageContext\n",
|
||||
"from llama_index.indices.vector_store import VectorStoreIndex\n",
|
||||
"from llama_index.vector_stores import SupabaseVectorStore\n",
|
||||
"import textwrap\n",
|
||||
"import html2text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "7a95a440",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Set up OpenAI\n",
|
||||
"\n",
|
||||
"LlamaIndex uses OpenAI GPT-3 `text-davinci-003` model. Let's store that in an environment variable:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ca2437d3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"os.environ['OPENAI_API_KEY'] = \"[your_openai_api_key]\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4dbd176f-3b4e-4d41-a72d-1e1affe6ecae",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Load the Dataset\n",
|
||||
"\n",
|
||||
"Let's load a small data set of Paul Graham's essays:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dc6b0bc2-b95f-4190-bf77-fa2dc57fc247",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"essays = [\n",
|
||||
" 'paul_graham_essay.txt'\n",
|
||||
"]\n",
|
||||
"documents = SimpleWebPageReader().load_data([f'https://raw.githubusercontent.com/supabase/supabase/master/examples/ai/llamaindex/data/{essay}' for essay in essays])\n",
|
||||
"print('Document ID:', documents[0].doc_id, 'Document Hash:', documents[0].doc_hash)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "955b2700-8242-40eb-ac3f-d479a0312693",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Create an index in Supabase\n",
|
||||
"\n",
|
||||
"Let's store Paul Graham's essays in Supabase. You can find the Postgres connection string in the [Database Settings](https://app.supabase.com/_/settings/database) of your Supabase project. This will work with all Postgres providers that support pgvector."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "ce9bc85b-e844-407c-a0ad-ccf6af3c8866",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"# Substitute your connection string here\n",
|
||||
"DB_CONNECTION = \"postgresql://postgres:password@localhost:5431/db\"\n",
|
||||
"\n",
|
||||
"vector_store = SupabaseVectorStore(\n",
|
||||
" postgres_connection_string=DB_CONNECTION, \n",
|
||||
" collection_name='base_demo'\n",
|
||||
")\n",
|
||||
"storage_context = StorageContext.from_defaults(vector_store=vector_store)\n",
|
||||
"index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "9e82862d-440a-4f66-9ed7-0eaa6a0f4062",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Query the index\n",
|
||||
"\n",
|
||||
"We can now ask questions using our index."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "d2771545-d209-4ceb-a222-ed139a4620f2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"query_engine = index.as_query_engine()\n",
|
||||
"\n",
|
||||
"# Ask a question\n",
|
||||
"response = query_engine.query(\"What did the author do growing up?\")\n",
|
||||
"\n",
|
||||
"# Print the response\n",
|
||||
"print(response)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+250
-207
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"vite": "^4.1.0"
|
||||
"vite": "^4.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -1546,9 +1546,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.0.tgz",
|
||||
"integrity": "sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.3.tgz",
|
||||
"integrity": "sha512-kLU+m2q0Y434Y1kCy3TchefAdtFso0ILi0dLyFV8Us3InXTU11H/B5ZTqCKIQHzSKNxVG/yEx813EA9f1imQ9A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
@@ -2681,9 +2681,9 @@
|
||||
}
|
||||
},
|
||||
"vite": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.0.tgz",
|
||||
"integrity": "sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.3.tgz",
|
||||
"integrity": "sha512-kLU+m2q0Y434Y1kCy3TchefAdtFso0ILi0dLyFV8Us3InXTU11H/B5ZTqCKIQHzSKNxVG/yEx813EA9f1imQ9A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild": "^0.17.5",
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"vite": "^4.1.0"
|
||||
"vite": "^4.2.3"
|
||||
}
|
||||
}
|
||||
+250
-207
@@ -15,7 +15,7 @@
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.0",
|
||||
"vite": "^3.2.7",
|
||||
"vite-plugin-solid": "^2.3.0"
|
||||
}
|
||||
},
|
||||
@@ -480,10 +480,26 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
|
||||
"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
|
||||
"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"
|
||||
],
|
||||
@@ -821,9 +837,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
|
||||
"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@@ -833,33 +849,34 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/linux-loong64": "0.14.54",
|
||||
"esbuild-android-64": "0.14.54",
|
||||
"esbuild-android-arm64": "0.14.54",
|
||||
"esbuild-darwin-64": "0.14.54",
|
||||
"esbuild-darwin-arm64": "0.14.54",
|
||||
"esbuild-freebsd-64": "0.14.54",
|
||||
"esbuild-freebsd-arm64": "0.14.54",
|
||||
"esbuild-linux-32": "0.14.54",
|
||||
"esbuild-linux-64": "0.14.54",
|
||||
"esbuild-linux-arm": "0.14.54",
|
||||
"esbuild-linux-arm64": "0.14.54",
|
||||
"esbuild-linux-mips64le": "0.14.54",
|
||||
"esbuild-linux-ppc64le": "0.14.54",
|
||||
"esbuild-linux-riscv64": "0.14.54",
|
||||
"esbuild-linux-s390x": "0.14.54",
|
||||
"esbuild-netbsd-64": "0.14.54",
|
||||
"esbuild-openbsd-64": "0.14.54",
|
||||
"esbuild-sunos-64": "0.14.54",
|
||||
"esbuild-windows-32": "0.14.54",
|
||||
"esbuild-windows-64": "0.14.54",
|
||||
"esbuild-windows-arm64": "0.14.54"
|
||||
"@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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -873,9 +890,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -889,9 +906,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
|
||||
"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
|
||||
"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"
|
||||
],
|
||||
@@ -905,9 +922,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
|
||||
"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"
|
||||
],
|
||||
@@ -921,9 +938,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
|
||||
"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"
|
||||
],
|
||||
@@ -937,9 +954,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
|
||||
"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"
|
||||
],
|
||||
@@ -953,9 +970,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
|
||||
"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
|
||||
"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"
|
||||
],
|
||||
@@ -969,9 +986,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
|
||||
"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
|
||||
"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"
|
||||
],
|
||||
@@ -985,9 +1002,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
|
||||
"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
|
||||
"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"
|
||||
],
|
||||
@@ -1001,9 +1018,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
|
||||
"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"
|
||||
],
|
||||
@@ -1017,9 +1034,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
|
||||
"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
|
||||
"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"
|
||||
],
|
||||
@@ -1033,9 +1050,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
|
||||
"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -1049,9 +1066,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
|
||||
"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
|
||||
"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"
|
||||
],
|
||||
@@ -1065,9 +1082,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
|
||||
"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
|
||||
"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"
|
||||
],
|
||||
@@ -1081,9 +1098,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1097,9 +1114,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
|
||||
"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"
|
||||
],
|
||||
@@ -1113,9 +1130,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
|
||||
"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
|
||||
"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"
|
||||
],
|
||||
@@ -1129,9 +1146,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
|
||||
"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
|
||||
"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"
|
||||
],
|
||||
@@ -1145,9 +1162,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
|
||||
"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -1161,9 +1178,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
|
||||
"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"
|
||||
],
|
||||
@@ -1354,10 +1371,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"
|
||||
},
|
||||
@@ -1418,9 +1441,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
|
||||
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
|
||||
"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": [
|
||||
{
|
||||
@@ -1430,10 +1453,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"
|
||||
},
|
||||
@@ -1474,9 +1501,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.77.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz",
|
||||
"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
|
||||
"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"
|
||||
@@ -1640,15 +1667,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||
"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.16",
|
||||
"esbuild": "^0.15.9",
|
||||
"postcss": "^8.4.18",
|
||||
"resolve": "^1.22.1",
|
||||
"rollup": ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
"rollup": "^2.79.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -1660,12 +1687,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
|
||||
},
|
||||
@@ -1675,6 +1707,9 @@
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
@@ -2089,10 +2124,17 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@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.54",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
|
||||
"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
|
||||
"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
|
||||
},
|
||||
@@ -2357,171 +2399,172 @@
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
|
||||
"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
|
||||
"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.54",
|
||||
"esbuild-android-64": "0.14.54",
|
||||
"esbuild-android-arm64": "0.14.54",
|
||||
"esbuild-darwin-64": "0.14.54",
|
||||
"esbuild-darwin-arm64": "0.14.54",
|
||||
"esbuild-freebsd-64": "0.14.54",
|
||||
"esbuild-freebsd-arm64": "0.14.54",
|
||||
"esbuild-linux-32": "0.14.54",
|
||||
"esbuild-linux-64": "0.14.54",
|
||||
"esbuild-linux-arm": "0.14.54",
|
||||
"esbuild-linux-arm64": "0.14.54",
|
||||
"esbuild-linux-mips64le": "0.14.54",
|
||||
"esbuild-linux-ppc64le": "0.14.54",
|
||||
"esbuild-linux-riscv64": "0.14.54",
|
||||
"esbuild-linux-s390x": "0.14.54",
|
||||
"esbuild-netbsd-64": "0.14.54",
|
||||
"esbuild-openbsd-64": "0.14.54",
|
||||
"esbuild-sunos-64": "0.14.54",
|
||||
"esbuild-windows-32": "0.14.54",
|
||||
"esbuild-windows-64": "0.14.54",
|
||||
"esbuild-windows-arm64": "0.14.54"
|
||||
"@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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
|
||||
"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
|
||||
"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
|
||||
"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
|
||||
"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
|
||||
"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
|
||||
"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
|
||||
"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
|
||||
"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
|
||||
"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
|
||||
"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
|
||||
"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
|
||||
"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
|
||||
},
|
||||
@@ -2653,9 +2696,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": {
|
||||
@@ -2695,12 +2738,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
|
||||
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
|
||||
"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"
|
||||
}
|
||||
@@ -2723,9 +2766,9 @@
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.77.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz",
|
||||
"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
|
||||
"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"
|
||||
@@ -2835,16 +2878,16 @@
|
||||
}
|
||||
},
|
||||
"vite": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||
"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.16",
|
||||
"postcss": "^8.4.18",
|
||||
"resolve": "^1.22.1",
|
||||
"rollup": ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
"rollup": "^2.79.1"
|
||||
}
|
||||
},
|
||||
"vite-plugin-solid": {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.0",
|
||||
"vite": "^3.2.7",
|
||||
"vite-plugin-solid": "^2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
+250
-207
@@ -18,13 +18,29 @@
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.7"
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
|
||||
"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
|
||||
"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"
|
||||
],
|
||||
@@ -428,9 +444,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
|
||||
"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@@ -440,33 +456,34 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/linux-loong64": "0.14.54",
|
||||
"esbuild-android-64": "0.14.54",
|
||||
"esbuild-android-arm64": "0.14.54",
|
||||
"esbuild-darwin-64": "0.14.54",
|
||||
"esbuild-darwin-arm64": "0.14.54",
|
||||
"esbuild-freebsd-64": "0.14.54",
|
||||
"esbuild-freebsd-arm64": "0.14.54",
|
||||
"esbuild-linux-32": "0.14.54",
|
||||
"esbuild-linux-64": "0.14.54",
|
||||
"esbuild-linux-arm": "0.14.54",
|
||||
"esbuild-linux-arm64": "0.14.54",
|
||||
"esbuild-linux-mips64le": "0.14.54",
|
||||
"esbuild-linux-ppc64le": "0.14.54",
|
||||
"esbuild-linux-riscv64": "0.14.54",
|
||||
"esbuild-linux-s390x": "0.14.54",
|
||||
"esbuild-netbsd-64": "0.14.54",
|
||||
"esbuild-openbsd-64": "0.14.54",
|
||||
"esbuild-sunos-64": "0.14.54",
|
||||
"esbuild-windows-32": "0.14.54",
|
||||
"esbuild-windows-64": "0.14.54",
|
||||
"esbuild-windows-arm64": "0.14.54"
|
||||
"@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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -480,9 +497,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -496,9 +513,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
|
||||
"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
|
||||
"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"
|
||||
],
|
||||
@@ -512,9 +529,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
|
||||
"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"
|
||||
],
|
||||
@@ -528,9 +545,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
|
||||
"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"
|
||||
],
|
||||
@@ -544,9 +561,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
|
||||
"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"
|
||||
],
|
||||
@@ -560,9 +577,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
|
||||
"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
|
||||
"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"
|
||||
],
|
||||
@@ -576,9 +593,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
|
||||
"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
|
||||
"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"
|
||||
],
|
||||
@@ -592,9 +609,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
|
||||
"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
|
||||
"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"
|
||||
],
|
||||
@@ -608,9 +625,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
|
||||
"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"
|
||||
],
|
||||
@@ -624,9 +641,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
|
||||
"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
|
||||
"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"
|
||||
],
|
||||
@@ -640,9 +657,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
|
||||
"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -656,9 +673,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
|
||||
"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
|
||||
"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"
|
||||
],
|
||||
@@ -672,9 +689,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
|
||||
"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
|
||||
"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"
|
||||
],
|
||||
@@ -688,9 +705,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -704,9 +721,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
|
||||
"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"
|
||||
],
|
||||
@@ -720,9 +737,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
|
||||
"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
|
||||
"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"
|
||||
],
|
||||
@@ -736,9 +753,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
|
||||
"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
|
||||
"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"
|
||||
],
|
||||
@@ -752,9 +769,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
|
||||
"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
|
||||
"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"
|
||||
],
|
||||
@@ -768,9 +785,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
|
||||
"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"
|
||||
],
|
||||
@@ -1104,10 +1121,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"
|
||||
},
|
||||
@@ -1213,9 +1236,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
|
||||
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
|
||||
"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": [
|
||||
{
|
||||
@@ -1225,10 +1248,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"
|
||||
},
|
||||
@@ -1317,9 +1344,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.77.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz",
|
||||
"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
|
||||
"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"
|
||||
@@ -1612,15 +1639,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||
"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.16",
|
||||
"esbuild": "^0.15.9",
|
||||
"postcss": "^8.4.18",
|
||||
"resolve": "^1.22.1",
|
||||
"rollup": ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
"rollup": "^2.79.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -1632,12 +1659,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
|
||||
},
|
||||
@@ -1647,6 +1679,9 @@
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
@@ -1711,10 +1746,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.54",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
|
||||
"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
|
||||
"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
|
||||
},
|
||||
@@ -2033,171 +2075,172 @@
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
|
||||
"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
|
||||
"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.54",
|
||||
"esbuild-android-64": "0.14.54",
|
||||
"esbuild-android-arm64": "0.14.54",
|
||||
"esbuild-darwin-64": "0.14.54",
|
||||
"esbuild-darwin-arm64": "0.14.54",
|
||||
"esbuild-freebsd-64": "0.14.54",
|
||||
"esbuild-freebsd-arm64": "0.14.54",
|
||||
"esbuild-linux-32": "0.14.54",
|
||||
"esbuild-linux-64": "0.14.54",
|
||||
"esbuild-linux-arm": "0.14.54",
|
||||
"esbuild-linux-arm64": "0.14.54",
|
||||
"esbuild-linux-mips64le": "0.14.54",
|
||||
"esbuild-linux-ppc64le": "0.14.54",
|
||||
"esbuild-linux-riscv64": "0.14.54",
|
||||
"esbuild-linux-s390x": "0.14.54",
|
||||
"esbuild-netbsd-64": "0.14.54",
|
||||
"esbuild-openbsd-64": "0.14.54",
|
||||
"esbuild-sunos-64": "0.14.54",
|
||||
"esbuild-windows-32": "0.14.54",
|
||||
"esbuild-windows-64": "0.14.54",
|
||||
"esbuild-windows-arm64": "0.14.54"
|
||||
"@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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
|
||||
"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
|
||||
"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
|
||||
"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
|
||||
"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
|
||||
"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
|
||||
"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
|
||||
"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
|
||||
"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
|
||||
"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
|
||||
"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
|
||||
"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
|
||||
"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.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
|
||||
"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
|
||||
},
|
||||
@@ -2454,9 +2497,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": {
|
||||
@@ -2526,12 +2569,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
|
||||
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
|
||||
"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"
|
||||
}
|
||||
@@ -2584,9 +2627,9 @@
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.77.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz",
|
||||
"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
|
||||
"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"
|
||||
@@ -2763,16 +2806,16 @@
|
||||
}
|
||||
},
|
||||
"vite": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||
"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.16",
|
||||
"postcss": "^8.4.18",
|
||||
"resolve": "^1.22.1",
|
||||
"rollup": ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
"rollup": "^2.79.1"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.7"
|
||||
"vite": "^3.2.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.0.4"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
+25
-17
@@ -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": {
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^3.1.0",
|
||||
"vite": "^3.1.0"
|
||||
"vite": "^3.2.7"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
## الحالة
|
||||
|
||||
- [x] طور الألفا: نحن نختبر Supabase مع مجموعة مغلقة من العملاء
|
||||
- [x] طور الألفا العام: يمكن لأي شخص الاشتراك في [app.supabase.com] (https://app.supabase.com). لكن تحلى بالصبر ، فهناك بعض العقد الصغيرة.
|
||||
- [x] طور الألفا العام: يمكن لأي شخص الاشتراك في [app.supabase.com](https://app.supabase.com). لكن تحلى بالصبر ، فهناك بعض العقد الصغيرة.
|
||||
- [x] طور البيتا العام: مستقر بدرجة كافية لمعظم حالات الاستخدام غير المتعلقة بالمؤسسات
|
||||
- [ ] الطور العام: جاهز للإنتاج
|
||||
|
||||
|
||||
+4
-4
@@ -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).
|
||||
|
||||

|
||||
|
||||
- [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.
|
||||
|
||||
+2
-2
@@ -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).
|
||||
|
||||

|
||||
|
||||
|
||||
+1
-1
@@ -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).
|
||||
|
||||
+3
-3
@@ -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).
|
||||
|
||||

|
||||
|
||||
- [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.
|
||||
|
||||
+8
-8
@@ -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).
|
||||
|
||||

|
||||
|
||||
- [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)
|
||||
|
||||
+1
-1
@@ -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).
|
||||
|
||||

|
||||
|
||||
+2
-2
@@ -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)]
|
||||
|
||||
|
||||
+2
-2
@@ -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.
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-1
@@ -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).
|
||||
|
||||

|
||||
|
||||
@@ -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).
|
||||
|
||||

|
||||
|
||||
@@ -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).
|
||||
|
||||

|
||||
|
||||
|
||||
+2
-2
@@ -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)]
|
||||
|
||||
|
||||
+8
-8
@@ -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).
|
||||
|
||||

|
||||
|
||||
- [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.
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+6
-6
@@ -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).
|
||||
|
||||

|
||||
@@ -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-шлюз.
|
||||
|
||||
#### Клієнтські бібліотеки
|
||||
|
||||
|
||||
+11
-11
@@ -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)
|
||||

|
||||
|
||||
## 文档
|
||||
|
||||
@@ -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)
|
||||

|
||||
|
||||
- [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)。你可以注册
|
||||
<tr>
|
||||
<th>语言</th>
|
||||
<th>客户端</th>
|
||||
<th colspan="5">特征-客户端(捆绑在Supabase客户端中)</th>
|
||||
<th colspan="5">特征-客户端(捆绑在Supabase客户端中)</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@@ -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://github.com/sponsors/supabase)
|
||||
[](https://github.com/sponsors/supabase)
|
||||
Generated
+6
@@ -722,6 +722,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",
|
||||
@@ -763,6 +764,7 @@
|
||||
"remark": "^13.0.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-html": "^15.0.1",
|
||||
"shared-data": "*",
|
||||
"swiper": "^6.5.0",
|
||||
"swr": "^0.5.4",
|
||||
"typescript": "^4.0.3",
|
||||
@@ -46590,6 +46592,7 @@
|
||||
"react-grid-layout": "^1.3.0",
|
||||
"react-hot-toast": "2.3.0",
|
||||
"react-inlinesvg": "^2.3.0",
|
||||
"react-intersection-observer": "^9.4.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-split": "^2.0.13",
|
||||
"react-tracked": "1.7.5",
|
||||
@@ -78796,6 +78799,7 @@
|
||||
"react-grid-layout": "^1.3.0",
|
||||
"react-hot-toast": "2.3.0",
|
||||
"react-inlinesvg": "^2.3.0",
|
||||
"react-intersection-observer": "*",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-split": "^2.0.13",
|
||||
"react-tracked": "1.7.5",
|
||||
@@ -82775,6 +82779,7 @@
|
||||
"www": {
|
||||
"version": "file:apps/www",
|
||||
"requires": {
|
||||
"@code-hike/mdx": "^0.8.3",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@mdx-js/loader": "^2.1.5",
|
||||
"@mdx-js/react": "^2.1.5",
|
||||
@@ -82832,6 +82837,7 @@
|
||||
"remark": "^13.0.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-html": "^15.0.1",
|
||||
"shared-data": "*",
|
||||
"swiper": "^6.5.0",
|
||||
"swr": "^0.5.4",
|
||||
"tailwindcss": "^3.1.8",
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"description": "Data shared between Supabase apps",
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
"scripts": {},
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@@ -7,24 +7,22 @@ interface AiIconProps {
|
||||
export const AiIcon = ({ className = 'text-brand-900' }: AiIconProps) => (
|
||||
<svg
|
||||
className={`w-6 h-6 ${className}`}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.7003 13.379L8.33022 14.9739C7.99629 15.3626 7.35899 15.1265 7.35899 14.614V10.2188L2.13597 10.2188C1.20712 10.2189 0.693015 9.14211 1.277 8.4198L7.24456 1.03867C7.5719 0.633801 8.22633 0.865262 8.22633 1.3859V5.71008H13.7967C14.7348 5.71008 15.2458 6.80561 14.6431 7.52442L14.1628 8.09707"
|
||||
stroke="#4CC38A"
|
||||
strokeMiterlimit="10"
|
||||
d="m10.618 11.832-2.283 2.657a.5.5 0 0 1-.88-.325v-3.98H2.728a1 1 0 0 1-.777-1.628l5.402-6.682a.5.5 0 0 1 .889.314v3.915h5.043a1 1 0 0 1 .766 1.642l-1.373 1.638"
|
||||
stroke-miterlimit="10"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
stroke="#4CC38A"
|
||||
strokeLinejoin="bevel"
|
||||
strokeMiterlimit="10"
|
||||
d="m12.232 14.15.418-1.254a2.383 2.383 0 0 1 1.507-1.507l1.253-.417-1.253-.418a2.383 2.383 0 0 1-1.508-1.507l-.417-1.253-.417 1.253a2.383 2.383 0 0 1-1.507 1.507l-1.253.418 1.253.417a2.383 2.383 0 0 1 1.507 1.507l.417 1.253Z"
|
||||
d="M12.2534 14.3848L12.5765 13.4148C12.7202 12.9836 12.9624 12.5917 13.2839 12.2702C13.6053 11.9488 13.9972 11.7066 14.4285 11.5628L15.3984 11.2398C15.5808 11.179 15.5808 10.921 15.3984 10.8603L14.4285 10.5372C13.9972 10.3935 13.6053 10.1513 13.2839 9.8298C12.9624 9.50834 12.7202 9.11646 12.5765 8.68518L12.2534 7.71525C12.1927 7.53285 11.9347 7.53285 11.8739 7.71525L11.5509 8.68518C11.4071 9.11646 11.1649 9.50834 10.8435 9.8298C10.522 10.1513 10.1301 10.3935 9.69885 10.5372L8.72892 10.8603C8.54652 10.921 8.54652 11.179 8.72892 11.2398L9.69885 11.5628C10.1301 11.7066 10.522 11.9488 10.8435 12.2702C11.1649 12.5917 11.4071 12.9836 11.5509 13.4148L11.8739 14.3848C11.9347 14.5672 12.1927 14.5672 12.2534 14.3848Z"
|
||||
fill="#4CC38A"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Props> = ({ 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 (
|
||||
<Transition
|
||||
@@ -31,17 +28,26 @@ const PlanSelection: FC<Props> = ({ visible, tiers, currentPlan, onSelectPlan })
|
||||
>
|
||||
<div>
|
||||
<h4 className="text-lg">Change your project's subscription</h4>
|
||||
<div className={`grid py-8 grid-cols-2 ${gridCols}`}>
|
||||
{formattedTiers.map((plan) => {
|
||||
return (
|
||||
<PlanCard
|
||||
key={plan.id}
|
||||
plan={plan}
|
||||
currentPlan={currentPlan}
|
||||
onSelectPlan={() => onSelectPlan(plan)}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<div className={`grid py-8 grid-cols-1 gap-8 md:grid-cols-3`}>
|
||||
{formattedTiers
|
||||
.filter((it) => it.name !== 'Enterprise')
|
||||
.map((plan) => {
|
||||
return (
|
||||
<PlanCard
|
||||
key={plan.id}
|
||||
plan={plan}
|
||||
currentPlan={currentPlan}
|
||||
onSelectPlan={() => onSelectPlan(plan)}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<PlanCardEnterprise
|
||||
plan={enterprisePlan}
|
||||
currentPlan={currentPlan}
|
||||
onSelectPlan={() => onSelectPlan(enterprisePlan)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-center items-center mt-4">
|
||||
<Link href="https://supabase.com/pricing">
|
||||
|
||||
@@ -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 (
|
||||
<Link href="https://forms.supabase.com/team">
|
||||
<a>
|
||||
<Button disabled={disabled} type={type} block>
|
||||
{ctaText}
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center space-y-2">
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
|
||||
@@ -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<Props> = ({ 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<Props> = ({ plan, currentPlan, onSelectPlan }) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'px-6 py-6 border rounded flex flex-col justify-between',
|
||||
`${isEnterprise ? 'bg-scale-200' : 'bg-scale-300'}`,
|
||||
`${isEnterprise && teamTierEnabled ? 'lg:col-span-3 xl:col-auto' : ''}`,
|
||||
].join(' ')}
|
||||
className={['px-6 py-6 border rounded flex flex-col justify-between bg-scale-300'].join(' ')}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'space-y-8',
|
||||
`${isEnterprise ? 'flex flex-col xl:space-x-0 xl:flex-col' : ''}`,
|
||||
`${isEnterprise && teamTierEnabled ? 'lg:flex-row lg:space-x-24' : ''}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'space-y-4',
|
||||
`${isEnterprise ? 'xl:w-auto' : ''}`,
|
||||
`${isEnterprise && teamTierEnabled ? 'xl:w-auto' : ''}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<div className={['space-y-8'].join(' ')}>
|
||||
<div className={['space-y-4'].join(' ')}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p
|
||||
className={[
|
||||
'text-brand-900 text-sm',
|
||||
`${isEnterprise ? 'lg:text-base xl:text-sm font-bold font-mono uppercase' : ''}`,
|
||||
].join(' ')}
|
||||
>
|
||||
{planMeta.name}
|
||||
</p>
|
||||
<p className={['text-brand-900 text-sm'].join(' ')}>{planMeta.name}</p>
|
||||
{isCurrentPlan ? (
|
||||
<div className="text-xs bg-scale-500 text-scale-1000 rounded px-2 py-0.5">
|
||||
Current plan
|
||||
@@ -66,16 +37,7 @@ const PlanCard: FC<Props> = ({ plan, currentPlan, onSelectPlan }) => {
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-scale-1100">{planMeta.description}</p>
|
||||
<div
|
||||
className={[
|
||||
'space-y-2',
|
||||
`${
|
||||
isEnterprise
|
||||
? 'pb-6 border-b lg:pt-6 lg:border-b-0 lg:border-t xl:pt-0 xl:pb-6 xl:border-t-0 xl:border-b'
|
||||
: 'border-b border-t py-8'
|
||||
}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<div className={['space-y-2', 'border-b border-t py-8'].join(' ')}>
|
||||
{planMeta.priceMonthly !== undefined ? (
|
||||
<>
|
||||
<p className="text-sm text-scale-1000">Starting from</p>
|
||||
@@ -92,15 +54,9 @@ const PlanCard: FC<Props> = ({ plan, currentPlan, onSelectPlan }) => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${isEnterprise ? 'lg:space-y-0 lg:!mt-0 xl:space-y-4' : 'space-y-4'}`}>
|
||||
<div className="space-y-4">
|
||||
<p className="text-xs text-scale-1000">{planMeta.preface}</p>
|
||||
<ul
|
||||
role="list"
|
||||
className={[
|
||||
`${isEnterprise ? 'xl:gap-0 xl:columns-1' : ''}`,
|
||||
`${isEnterprise && teamTierEnabled ? 'lg:gap-16 lg:columns-2' : ''}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<ul role="list">
|
||||
{planMeta.features.map((feature) => (
|
||||
<li key={feature} className="flex py-2">
|
||||
<div className="w-[12px]">
|
||||
@@ -116,35 +72,34 @@ const PlanCard: FC<Props> = ({ plan, currentPlan, onSelectPlan }) => {
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{!isEnterprise && (
|
||||
<div className="space-y-4 !mt-20">
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-scale-1000">{planMeta.scale}</p>
|
||||
|
||||
{planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO && (
|
||||
<div>
|
||||
<p className="text-sm text-scale-1100">
|
||||
Need more? Turn off your spend cap to Pay As You Grow
|
||||
</p>
|
||||
<p className="text-xs text-scale-1000">
|
||||
Additional fees apply for spend beyond the limits above
|
||||
</p>{' '}
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-4 !mt-20">
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-scale-1000">{planMeta.scale}</p>
|
||||
|
||||
{planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PAYG && (
|
||||
<div>
|
||||
<p className="text-sm text-scale-1100">Spend cap is currently disabled</p>
|
||||
<p className="text-xs text-scale-1000">
|
||||
You will be charged for usage beyond the plan limits
|
||||
</p>{' '}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PRO && (
|
||||
<div>
|
||||
<p className="text-sm text-scale-1100">
|
||||
Need more? Turn off your spend cap to Pay As You Grow
|
||||
</p>
|
||||
<p className="text-xs text-scale-1000">
|
||||
Additional fees apply for spend beyond the limits above
|
||||
</p>{' '}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<PlanCTAButton plan={plan} currentPlan={currentPlan} onSelectPlan={onSelectPlan} />
|
||||
{planMeta.name === 'Pro' && currentPlan?.prod_id === STRIPE_PRODUCT_IDS.PAYG && (
|
||||
<div>
|
||||
<p className="text-sm text-scale-1100">Spend cap is currently disabled</p>
|
||||
<p className="text-xs text-scale-1000">
|
||||
You will be charged for usage beyond the plan limits
|
||||
</p>{' '}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<PlanCTAButton plan={plan} currentPlan={currentPlan} onSelectPlan={onSelectPlan} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<Props> = ({ 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 (
|
||||
<div className="px-6 py-6 border rounded flex-col bg-scale-200 flex">
|
||||
<div className="space-y-8">
|
||||
<div className=" grid grid-cols-3 space-x-8">
|
||||
<div className="space-y-4 pr-14">
|
||||
<div className="flex items-center ">
|
||||
<p className="text-brand-900 text-sm">{planMeta.name}</p>
|
||||
{isCurrentPlan ? (
|
||||
<div className="text-xs bg-scale-500 text-scale-1000 rounded px-2 py-0.5">
|
||||
Current plan
|
||||
</div>
|
||||
) : planMeta.new ? (
|
||||
<div className="text-xs bg-brand-400 text-brand-900 rounded px-2 py-0.5">New</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-scale-1100">{planMeta.description}</p>
|
||||
<div className="space-y-2 border-t pb-6 lg:pt-6 xl:pt-0 xl:pb-6">
|
||||
<PlanCTAButton plan={plan} currentPlan={currentPlan} onSelectPlan={onSelectPlan} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4 lg:col-span-2">
|
||||
<p className="text-xs text-scale-1000">{planMeta.preface}</p>
|
||||
<ul role="list" className="text-xs text-scale-1000 md:grid md:grid-cols-2 md:gap-x-10">
|
||||
{planMeta.features.map((feature) => (
|
||||
<li key={feature} className="flex items-center py-2 first:mt-0">
|
||||
<IconCheck
|
||||
className="text-brand-900 h-4 w-4"
|
||||
aria-hidden="true"
|
||||
strokeWidth={3}
|
||||
/>
|
||||
<span className="dark:text-scale-1200 mb-0 ml-3 ">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlanCardEnterprise
|
||||
@@ -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`,
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -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<string | null>(null)
|
||||
const captchaRef = useRef<HCaptcha>(null)
|
||||
|
||||
@@ -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',
|
||||
]
|
||||
@@ -11,7 +11,7 @@ const ProjectUpdateDisabledTooltip = ({
|
||||
}: PropsWithChildren<ProjectUpdateDisabledTooltipProps>) => {
|
||||
return (
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger>{children}</Tooltip.Trigger>
|
||||
<Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
|
||||
{projectUpdateDisabled ? (
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="bottom">
|
||||
|
||||
@@ -42,10 +42,10 @@ 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 &&
|
||||
isUsageBillingEnabled === false &&
|
||||
Object.values(usage ?? {})
|
||||
.map((metric) => {
|
||||
if (typeof metric !== 'object') return false
|
||||
@@ -77,13 +77,14 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => {
|
||||
{isUsageBillingEnabled ? (
|
||||
<p className="text-sm text-scale-1000">
|
||||
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.
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm text-scale-1000">
|
||||
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.
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -96,7 +97,7 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => {
|
||||
<Button
|
||||
key="upgrade-button"
|
||||
type="default"
|
||||
className="ml-4"
|
||||
className="ml-8"
|
||||
onClick={() =>
|
||||
snap.setPanelKey(
|
||||
currentPlan?.id === 'free' ? 'subscriptionPlan' : 'costControl'
|
||||
@@ -110,7 +111,7 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => {
|
||||
Your project can become unresponsive or enter read only mode.{' '}
|
||||
{currentPlan?.id === 'free'
|
||||
? 'Please upgrade to the Pro plan to ensure that your project remains available.'
|
||||
: 'Please disable spend caps to ensure that your project remains available.'}
|
||||
: 'Please disable spend cap to ensure that your project remains available.'}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
@@ -149,8 +150,8 @@ const BillingBreakdown = ({}: BillingBreakdownProps) => {
|
||||
<div
|
||||
key={metric.key}
|
||||
className={clsx(
|
||||
'col-span-6 space-y-4 py-4 border-scale-400',
|
||||
i % 2 === 0 ? 'border-r pr-4' : 'pl-4',
|
||||
'col-span-12 md:col-span-6 space-y-4 py-4 border-scale-400',
|
||||
i % 2 === 0 ? 'md:border-r md:pr-4' : 'md:pl-4',
|
||||
i < BILLING_BREAKDOWN_METRICS.length - 2 && 'border-b'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,66 +1,60 @@
|
||||
import clsx from 'clsx'
|
||||
import { Button, IconCheck } from 'ui'
|
||||
import { PricingInformation } from './Tier.constants'
|
||||
import Link from 'next/link'
|
||||
import { PricingInformation } from 'shared-data'
|
||||
|
||||
export interface EnterpriseCardProps {
|
||||
plan: PricingInformation
|
||||
isCurrentPlan: boolean
|
||||
isTeamTierEnabled: boolean
|
||||
}
|
||||
|
||||
const EnterpriseCard = ({ plan, isCurrentPlan, isTeamTierEnabled }: EnterpriseCardProps) => {
|
||||
const EnterpriseCard = ({ plan, isCurrentPlan }: EnterpriseCardProps) => {
|
||||
return (
|
||||
<div
|
||||
key={plan.id}
|
||||
className={clsx(
|
||||
'flex border rounded-md bg-scale-200',
|
||||
isTeamTierEnabled
|
||||
? 'px-12 py-8 col-span-12 justify-between'
|
||||
: 'px-6 py-6 col-span-4 flex-col'
|
||||
'grid grid-cols-1 md:grid-cols-3 border rounded-md bg-scale-200',
|
||||
'py-4 col-span-12 justify-between gap-x-8'
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-col justify-center px-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className={clsx('text-brand-900 text-sm uppercase')}>{plan.name}</p>
|
||||
{isCurrentPlan ? (
|
||||
<div className="text-xs bg-scale-500 text-scale-1000 rounded px-2 py-0.5">
|
||||
Current plan
|
||||
</div>
|
||||
) : plan.new ? (
|
||||
<div className="text-xs bg-brand-400 text-brand-900 rounded px-2 py-0.5">New</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
) : plan.nameBadge ? (
|
||||
<div className="text-xs bg-brand-400 text-brand-900 rounded px-2 py-0.5">
|
||||
{plan.nameBadge}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<p className="text-sm mt-2 mb-4">{plan.preface}</p>
|
||||
<p className="text-sm mt-2 mb-4">{plan.description}</p>
|
||||
|
||||
<Link href="https://supabase.com/contact/enterprise">
|
||||
<a target="blank" rel="noreferrer">
|
||||
<Button block={!isTeamTierEnabled} type="default">
|
||||
Contact Sales Team
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
<a href={plan.href} className="hidden md:block" target="_blank">
|
||||
<Button block type="default" size="tiny">
|
||||
{plan.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{!isTeamTierEnabled && <div className="border-t my-6" />}
|
||||
<div className="flex flex-col justify-center col-span-2 px-4 md:px-0">
|
||||
<ul role="list" className="text-xs text-scale-1000 md:grid md:grid-cols-2 md:gap-x-10">
|
||||
{plan.features.map((feature) => (
|
||||
<li key={feature} className="flex items-center py-2 first:mt-0">
|
||||
<IconCheck className="text-brand-900 h-4 w-4" aria-hidden="true" strokeWidth={3} />
|
||||
<span className="dark:text-scale-1200 mb-0 ml-3 ">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<ul role="list" className={clsx(isTeamTierEnabled && 'pr-12')}>
|
||||
{plan.features.map((feature) => (
|
||||
<li key={feature} className="flex py-2">
|
||||
<div className="w-[12px]">
|
||||
<IconCheck
|
||||
className="h-3 w-3 text-brand-900 translate-y-[2.5px]"
|
||||
aria-hidden="true"
|
||||
strokeWidth={3}
|
||||
/>
|
||||
</div>
|
||||
<p className="ml-3 text-xs text-scale-1100">{feature}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<a href={plan.href} className="visible md:hidden mt-8" target="_blank">
|
||||
<Button block type="default" size="tiny">
|
||||
{plan.cta}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { ProjectSubscriptionResponse } from 'data/subscriptions/project-subscription-v2-query'
|
||||
import { Button, IconCreditCard, IconFileText, Modal } from 'ui'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { useState } from 'react'
|
||||
import PaymentMethodSelection from './PaymentMethodSelection'
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
SubscriptionTier,
|
||||
updateSubscriptionTier,
|
||||
} from 'data/subscriptions/project-subscription-update-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
|
||||
export interface SubscriptionTierProps {
|
||||
subscription: ProjectSubscriptionResponse
|
||||
}
|
||||
|
||||
const SubscriptionPaymentMethod = ({ subscription }: SubscriptionTierProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { ui } = useStore()
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [showPaymentEditModal, setShowPaymentEditModal] = useState(false)
|
||||
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState<string>(
|
||||
subscription.payment_method_id || ''
|
||||
)
|
||||
|
||||
const onConfirmPaymentMethod = async () => {
|
||||
setIsSubmitting(true)
|
||||
|
||||
if (selectedPaymentMethod) {
|
||||
if (!projectRef) return console.error('Project ref is required')
|
||||
if (!selectedPaymentMethod) {
|
||||
return ui.setNotification({ category: 'error', message: 'Please select a payment method' })
|
||||
}
|
||||
|
||||
const selectedTier =
|
||||
subscription.plan.id === 'pro' && subscription.usage_billing_enabled
|
||||
? 'tier_payg'
|
||||
: `tier_${subscription.plan.id}`
|
||||
|
||||
try {
|
||||
setIsSubmitting(true)
|
||||
await updateSubscriptionTier({
|
||||
projectRef,
|
||||
tier: selectedTier as SubscriptionTier,
|
||||
paymentMethod: selectedPaymentMethod,
|
||||
})
|
||||
|
||||
setShowPaymentEditModal(false)
|
||||
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated payment method!`,
|
||||
})
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Unable to update subscription: ${error.message}`,
|
||||
})
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
|
||||
if (subscription.payment_method_type === 'none') return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<Panel>
|
||||
<Panel.Content className="flex justify-between lg:items-center flex-col md:flex-row space-y-6 md:space-y-0">
|
||||
{subscription.payment_method_type === 'card' && (
|
||||
<>
|
||||
<div className="flex space-x-3 items-center font-mono tracking-wide text-scale-1000">
|
||||
{subscription.payment_method_card_details?.brand ? (
|
||||
<img
|
||||
alt="Credit card brand"
|
||||
src={`${BASE_PATH}/img/payment-methods/${subscription.payment_method_card_details?.brand
|
||||
.replace(' ', '-')
|
||||
.toLowerCase()}.png`}
|
||||
width="32"
|
||||
/>
|
||||
) : (
|
||||
<IconCreditCard />
|
||||
)}
|
||||
<span>
|
||||
**** **** ****{' '}
|
||||
{subscription?.payment_method_card_details?.last_4_digits || '****'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-row space-x-3 text-scale-1000">
|
||||
<span>
|
||||
Expires {subscription?.payment_method_card_details?.expiry_month || '-'}/
|
||||
{subscription?.payment_method_card_details?.expiry_year?.toString()?.slice(-2) ||
|
||||
'-'}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{subscription?.payment_method_type === 'invoice' && (
|
||||
<>
|
||||
<div className="flex space-x-3">
|
||||
<div >
|
||||
<p className="text-scale-1100">Payment via invoice</p>
|
||||
<p className="text-sm text-scale-1000">You get a monthly invoice and payment link via email.</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<div>
|
||||
<Button
|
||||
type="default"
|
||||
disabled={subscription?.payment_method_type !== 'card'}
|
||||
onClick={() => setShowPaymentEditModal(true)}
|
||||
>
|
||||
Change
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip.Trigger>
|
||||
{subscription?.payment_method_type !== 'card' && (
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-scale-100 py-1 px-2 leading-none shadow',
|
||||
'border border-scale-200',
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-scale-1200">
|
||||
Please email support@supbase.io to change your payment method.
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
)}
|
||||
</Tooltip.Root>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
|
||||
<Modal
|
||||
loading={isSubmitting}
|
||||
alignFooter="right"
|
||||
className="!w-[450px]"
|
||||
visible={showPaymentEditModal}
|
||||
onCancel={() => setShowPaymentEditModal(false)}
|
||||
onConfirm={onConfirmPaymentMethod}
|
||||
overlayClassName="pointer-events-none"
|
||||
header={`Change payment method`}
|
||||
>
|
||||
<Modal.Content>
|
||||
<div className="py-6 space-y-2">
|
||||
<p className="text-sm">
|
||||
Upon clicking confirm, your next and future invoices will be deducted from the
|
||||
selected payment method. There are no immediate charges.
|
||||
</p>
|
||||
<div className="!mt-6">
|
||||
<PaymentMethodSelection
|
||||
selectedPaymentMethod={selectedPaymentMethod}
|
||||
onSelectPaymentMethod={setSelectedPaymentMethod}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SubscriptionPaymentMethod
|
||||
@@ -4,16 +4,19 @@ import SparkBar from 'components/ui/SparkBar'
|
||||
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
|
||||
import dayjs from 'dayjs'
|
||||
import { useSubscriptionPageStateSnapshot } from 'state/subscription-page'
|
||||
import { Alert, Button } from 'ui'
|
||||
import { Alert, Button, IconExternalLink } from 'ui'
|
||||
import TierUpdateSidePanel from './TierUpdateSidePanel'
|
||||
import Link from 'next/link'
|
||||
import { useFlag } from 'hooks'
|
||||
import { useFlag, useStore } from 'hooks'
|
||||
import ProjectUpdateDisabledTooltip from '../../ProjectUpdateDisabledTooltip'
|
||||
import SubscriptionPaymentMethod from './SubscriptionPaymentMethod'
|
||||
|
||||
export interface SubscriptionTierProps {}
|
||||
|
||||
const SubscriptionTier = ({}: SubscriptionTierProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { ui } = useStore()
|
||||
const orgSlug = ui.selectedOrganization?.slug ?? ''
|
||||
const snap = useSubscriptionPageStateSnapshot()
|
||||
const projectUpdateDisabled = useFlag('disableProjectCreationAndUpdate')
|
||||
const { data: subscription, isLoading } = useProjectSubscriptionV2Query({ projectRef })
|
||||
@@ -32,8 +35,33 @@ const SubscriptionTier = ({}: SubscriptionTierProps) => {
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-12 gap-6" id="plan">
|
||||
<div className="col-span-12 lg:col-span-5">
|
||||
<p className="text-base sticky top-16">Subscription plan</p>
|
||||
<div className="col-span-12 lg:col-span-5 space-y-6">
|
||||
<div className="sticky space-y-6 top-16">
|
||||
<p className="text-base">Subscription plan</p>
|
||||
<div className="text-sm text-scale-1000">
|
||||
To manage your billing address, emails or Tax ID, head to your{' '}
|
||||
<Link href={`/org/${orgSlug}/billing`}>
|
||||
<a>
|
||||
<span className="text-sm text-green-900 transition hover:text-green-1000">
|
||||
organization settings
|
||||
</span>.
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-scale-1100">More information</p>
|
||||
<div>
|
||||
<Link href="https://supabase.com/pricing">
|
||||
<a target="_blank" rel="noreferrer">
|
||||
<div className="flex items-center space-x-2 opacity-50 hover:opacity-100 transition">
|
||||
<p className="text-sm">Pricing</p>
|
||||
<IconExternalLink size={16} strokeWidth={1.5} />
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className="col-span-12 lg:col-span-7 space-y-2">
|
||||
@@ -87,7 +115,7 @@ const SubscriptionTier = ({}: SubscriptionTierProps) => {
|
||||
{!subscription?.usage_billing_enabled && (
|
||||
<Alert withIcon variant="info" title="This project is limited by the included usage">
|
||||
<p className="text-sm text-scale-1000">
|
||||
When this project exceeds its included usage quotas, it may become unresponsive.
|
||||
When this project exceeds its included usage quotas, it may become unresponsive.{' '}
|
||||
{currentPlan?.id === 'free'
|
||||
? 'If you wish to exceed the included usage, you should upgrade to a paid plan.'
|
||||
: 'You can change the Cost Control settings if you plan on exceeding the included usage quotas.'}
|
||||
@@ -106,6 +134,8 @@ const SubscriptionTier = ({}: SubscriptionTierProps) => {
|
||||
labelBottomClass="!text-scale-1000 pb-1"
|
||||
labelTop={`${daysToCycleEnd} Days left`}
|
||||
/>
|
||||
|
||||
{subscription && <SubscriptionPaymentMethod subscription={subscription} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -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',
|
||||
]
|
||||
@@ -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, STRIPE_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 = () => {
|
||||
>
|
||||
<SidePanel.Content>
|
||||
<div className="py-6 grid grid-cols-12 gap-3">
|
||||
{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 (
|
||||
<EnterpriseCard
|
||||
key={plan.id}
|
||||
plan={plan}
|
||||
isCurrentPlan={isCurrentPlan}
|
||||
isTeamTierEnabled={teamTierEnabled}
|
||||
/>
|
||||
)
|
||||
return <EnterpriseCard key={plan.id} plan={plan} isCurrentPlan={isCurrentPlan} />
|
||||
}
|
||||
|
||||
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 = () => {
|
||||
<div className="text-xs bg-scale-500 text-scale-1000 rounded px-2 py-0.5">
|
||||
Current plan
|
||||
</div>
|
||||
) : plan.new ? (
|
||||
) : plan.nameBadge ? (
|
||||
<div className="text-xs bg-brand-400 text-brand-900 rounded px-2 py-0.5">
|
||||
New
|
||||
{plan.nameBadge}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
@@ -169,32 +160,38 @@ const TierUpdateSidePanel = () => {
|
||||
) : (
|
||||
<p className="text-scale-1200 text-lg">${price}</p>
|
||||
)}
|
||||
<p className="text-scale-1000 text-sm">per month</p>
|
||||
<p className="text-scale-1000 text-sm">{tierMeta?.costUnit}</p>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'flex mt-1 mb-4',
|
||||
plan.id !== PRICING_TIER_PRODUCT_IDS.TEAM && 'opacity-0'
|
||||
)}
|
||||
>
|
||||
<div className="text-xs bg-brand-400 text-brand-900 rounded px-2 py-0.5">
|
||||
Usage based plan
|
||||
<div className={clsx('flex mt-1 mb-4', !tierMeta?.warning && 'opacity-0')}>
|
||||
<div className="bg-scale-200 text-brand-1100 border shadow-sm rounded-md bg-opacity-30 py-0.5 px-2 text-xs">
|
||||
{tierMeta?.warning}
|
||||
</div>
|
||||
</div>
|
||||
{isCurrentPlan ? (
|
||||
<Button block disabled type="default">
|
||||
Current plan
|
||||
</Button>
|
||||
) : (
|
||||
) : plan.id !== PRICING_TIER_PRODUCT_IDS.TEAM ? (
|
||||
<Button
|
||||
block
|
||||
// no self-serve downgrades from team plan right now
|
||||
disabled={
|
||||
plan.id !== PRICING_TIER_PRODUCT_IDS.TEAM &&
|
||||
['team', 'enterprise'].includes(subscription?.plan?.id || '')
|
||||
}
|
||||
type={isDowngradeOption ? 'default' : 'primary'}
|
||||
loading={isLoading}
|
||||
disabled={isLoading}
|
||||
onClick={() => setSelectedTier(plan.id as any)}
|
||||
>
|
||||
{isDowngradeOption ? 'Downgrade' : 'Upgrade'} to {plan.name}
|
||||
</Button>
|
||||
) : (
|
||||
<Link href={plan.href} passHref className="hidden md:block">
|
||||
<a target="_blank">
|
||||
<Button block type="primary">
|
||||
Contact Us
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<div className="border-t my-6" />
|
||||
|
||||
@@ -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 (
|
||||
<UsageSection
|
||||
projectRef={projectRef}
|
||||
categoryKey='activity'
|
||||
categoryKey="activity"
|
||||
chartMeta={chartMeta}
|
||||
subscription={subscription}
|
||||
currentBillingCycleSelected={currentBillingCycleSelected}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Loaded 100 of 129 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user