diff --git a/apps/database-new/package.json b/apps/database-new/package.json index 44b5b6d4300..ea879606f3d 100644 --- a/apps/database-new/package.json +++ b/apps/database-new/package.json @@ -19,10 +19,10 @@ "common": "*", "config": "*", "dayjs": "^1.11.10", - "eslint-config-next": "^14.1.0", + "eslint-config-next": "^14.1.4", "lodash": "^4.17.21", "lucide-react": "^0.338.0", - "next": "^14.0.3", + "next": "^14.1.4", "openai": "^4.20.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -38,7 +38,7 @@ "@types/react": "^18.2.24", "@types/react-dom": "^18.2.8", "autoprefixer": "^10.4.14", - "nextjs-node-loader": "^1.1.5-alpha.0", + "nextjs-node-loader": "^1.1.5", "postcss": "^8.4.31", "typescript": "^5.4.3" } diff --git a/apps/docs/components/Feedback/Feedback.tsx b/apps/docs/components/Feedback/Feedback.tsx index 96137bfd4a1..0359b20e360 100644 --- a/apps/docs/components/Feedback/Feedback.tsx +++ b/apps/docs/components/Feedback/Feedback.tsx @@ -10,7 +10,7 @@ import { useState, } from 'react' -import { useIsLoggedIn } from 'common' +import { type Database, useIsLoggedIn } from 'common' import { Button, cn } from 'ui' import { useSendFeedbackMutation } from '~/lib/fetch/feedback' @@ -76,7 +76,7 @@ function Feedback() { const pathname = usePathname() const sendTelemetryEvent = useSendTelemetryEvent() const { mutate: sendFeedbackComment } = useSendFeedbackMutation() - const supabase = useSupabaseClient() + const supabase = useSupabaseClient() const unanswered = state.type === 'unanswered' const isYes = 'response' in state && state.response === 'yes' @@ -85,7 +85,13 @@ function Feedback() { const showNo = unanswered || isNo async function sendFeedbackVote(response: Response) { - const { error } = await supabase.from('feedback').insert({ vote: response, page: pathname }) + const { error } = await supabase.from('feedback').insert({ + vote: response, + page: pathname, + metadata: { + query: Object.fromEntries(new URLSearchParams(window.location.search).entries()), + }, + }) if (error) console.error(error) } @@ -111,8 +117,14 @@ function Feedback() { }, 100) } - async function handleSubmit({ page, comment }: FeedbackFields) { - sendFeedbackComment({ message: comment, pathname: page }) + async function handleSubmit({ page, comment, title }: FeedbackFields) { + sendFeedbackComment({ + message: comment, + pathname: page, + title, + // @ts-expect-error -- can't click this button without having a state.response + isHelpful: state.response === 'yes', + }) setModalOpen(false) refocusButton() } @@ -178,14 +190,12 @@ function Feedback() { )} > Thanks for your feedback! - {/** setModalOpen(true)} isYes={isYes} visible={!unanswered} /> - */} { const errors: Partial = {} + if (!vals.title) { + errors.title = 'Required' + } + if (!vals.comment) { errors.comment = 'Required' } @@ -32,8 +37,9 @@ function FeedbackModal({ visible, page, onCancel, onSubmit }: FeedbackModalProps > {({ isSubmitting }: { isSubmitting: boolean }) => ( <> - + + { // [Joshen] We will still provide support for headers declared like this: @@ -28,30 +37,91 @@ const formatTOCHeader = (content: string) => { return res.join('') } -interface TOCHeader { - id: number - level: number - text: string - link: string -} +const GuidesTableOfContents = ({ + className, + overrideToc, + video, +}: { + className?: string + overrideToc?: Array<{ text: string; link: string; level: number }> + video?: string +}) => { + const [tocList, setTocList] = useState([]) + const pathname = usePathname() + const [hash] = useHash() -interface Props { - list: TOCHeader[] -} + const displayedList = overrideToc ?? tocList + + useEffect(() => { + if (overrideToc) return + + /** + * Because we're directly querying the DOM, needs the setTimeout so the DOM + * update will happen first. + */ + const timeoutHandle = setTimeout(() => { + const headings = Array.from( + document.querySelector('#sb-docs-guide-main-article')?.querySelectorAll('h2, h3') ?? [] + ) + const newHeadings = headings + .filter((heading) => heading.id) + .map((heading) => { + const text = heading.textContent.replace('#', '') + const link = heading.querySelector('a').getAttribute('href') + const level = heading.tagName === 'H2' ? 2 : 3 + return { text, link, level } + }) + setTocList(newHeadings) + }) + + return () => clearTimeout(timeoutHandle) + /** + * window.location.href needed to recalculate toc when page changes, + * useRerenderOnEvt below will guarantee rerender on change + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [overrideToc, typeof window !== 'undefined' && window.location.href]) + + useEffect(() => { + if (hash && displayedList.length > 0) { + highlightSelectedTocItem(hash) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [hash, JSON.stringify(displayedList)]) + + /** + * Displayed headings may change if the tab changes, so the table of contents + * needs to rerender. + */ + useRerenderOnEvt(TAB_CHANGE_EVENT_NAME) + + if (!displayedList.length) return + + const tocVideoPreview = `http://img.youtube.com/vi/${video}/0.jpg` -const GuidesTableOfContents: FC = ({ list }) => { return ( - + ) } diff --git a/apps/docs/components/MDX/social_provider_setup.mdx b/apps/docs/components/MDX/social_provider_setup.mdx index 6adc01d926b..b270d56d745 100644 --- a/apps/docs/components/MDX/social_provider_setup.mdx +++ b/apps/docs/components/MDX/social_provider_setup.mdx @@ -3,4 +3,4 @@ The next step requires a callback URL, which looks like this: `https:// + return case 'getting-started': - return + return case 'database': - return + return case 'rest': - return + return case 'graphql': - return + return case 'auth': - return + return case 'edge-functions': - return + return case 'realtime': - return + return case 'storage': - return + return case 'ai': - return + return case 'platform': - return + return case 'resources': - return + return case 'self-hosting': - return + return case 'integrations': - return + return case 'reference-javascript': - return + return case 'reference-dart': - return + return case 'reference-python': - return + return case 'reference-csharp': - return + return case 'reference-swift': - return + return case 'reference-kotlin': - return + return case 'reference-api': - return + return case 'dev-cli': - return + return case 'reference-cli': - return + return case 'status': - return + return default: - return + return } } @@ -85,12 +85,14 @@ type HomeMenuIconPickerProps = { icon: string width?: number height?: number + className?: string } export default function HomeMenuIconPicker({ icon, width = 16, height = 16, + className, }: HomeMenuIconPickerProps) { - return getMenuIcon(icon, width, height) + return getMenuIcon(icon, width, height, className) } diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx index d2b0636a8b7..e762f8f3c78 100644 --- a/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx @@ -3,11 +3,13 @@ import { products } from 'shared-data' type HomeMenuIcon = { width?: number height?: number + className?: string } -export function IconMenuHome({ width = 16, height = 16 }: HomeMenuIcon) { +export function IconMenuHome({ width = 16, height = 16, className }: HomeMenuIcon) { return ( { - // [Joshen] We will still provide support for headers declared like this: - // ## REST API {#rest-api-overview} - // At least for now, this was a docusaurus thing. - if (slug.includes('#')) return slug.split('-#')[1] - return slug -} - -const formatTOCHeader = (content: string) => { - let begin = false - const res = [] - for (const x of content) { - if (x === '`') { - if (!begin) { - begin = true - res.push(``) - } else { - begin = false - res.push(``) - } - } else { - res.push(x) - } - } - return res.join('') -} - -const TableOfContents: FC = ({ toc, video }) => { - // [Joshen] markdown-toc doesn't seem to read maxdepth from the options passed in - // Our first level headers will be H2s (H1 is ignored), and we only show up to H3 - - return ( - <> - {video && ( -
- -
- )} -
- - ) -} - -export default TableOfContents diff --git a/apps/docs/content/guides/auth/auth-anonymous.mdx b/apps/docs/content/guides/auth/auth-anonymous.mdx index b4f902eae1f..a7c35c2ade2 100644 --- a/apps/docs/content/guides/auth/auth-anonymous.mdx +++ b/apps/docs/content/guides/auth/auth-anonymous.mdx @@ -22,7 +22,7 @@ This is different from the `anon` API key which does not create a user and can b -To get started, [enable anonymous sign-ins](/dashboard/project/_/auth/providers) for your Supabase Project. +To get started, [enable anonymous sign-ins](/dashboard/project/_/settings/auth) for your Supabase Project. @@ -55,6 +55,15 @@ Call the [`signInAnonymously()`](/docs/reference/javascript/auth-signinanonymous const { data, error } = await supabase.auth.signInAnonymously() ``` + + + +Call the [`signInAnonymously()`](/docs/reference/kotlin/auth-signinanonymously) method: + +```kotlin +supabase.auth.signInAnonymously() +``` + @@ -79,6 +88,17 @@ You can use the [`updateUser()`](/docs/reference/javascript/auth-updateuser) met const { data, error } = await supabase.auth.updateUser({ email: 'example@email.com' }) ``` + + + +You can use the [`modifyUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user. + +```kotlin +supabase.auth.modifyUser { + email = "example@email.com" +} +``` + @@ -99,6 +119,15 @@ You can use the [`linkIdentity()`](/docs/reference/javascript/auth-linkidentity) const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' }) ``` + + + +You can use the [`linkIdentity()`](/docs/reference/kotlin/auth-linkidentity) method to link an oauth identity to the anonymous user. + +```kotlin +supabase.auth.linkIdentity(Google) +``` + @@ -108,7 +137,7 @@ An anonymous user assumes the `authenticated` role just like a permanent user. Y ```sql create policy "Only permanent users can post to the news feed" -on news_feed for insert +on news_feed as restrictive for insert to authenticated with check ((auth.jwt()->>'is_anonymous')::boolean is false ); @@ -118,6 +147,12 @@ to authenticated using ( true ); ``` + + +RLS policies are permissive by default, which means that they are combined using an "OR" operator when multiple policies are applied. It is important to construct restrictive policies to ensure that the checks for an anonymous user are always enforced when combined with other policies. + + + ## Resolving identity conflicts Depending on your application requirements, data conflicts can arise when an anonymous user is converted to a permanent user. For example, in the context of an e-commerce application, an anonymous user would be allowed to add items to the shopping cart without signing up / signing in. When they decide to sign-in to an existing account, you will need to decide how you want to resolve data conflicts in the shopping cart: diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx index abdd657a63c..d817f0bc973 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx @@ -11,6 +11,20 @@ The `auth-helpers` package has been replaced with the `@supabase/ssr` package. W + + + + This submodule provides convenience helpers for implementing user authentication in Next.js applications using the pages directory. > Note: As of [Next.js 13.4](https://nextjs.org/blog/next-13-4), the App Router has reached stable status. This is now the recommended path for new Next.js app. Check out our guide on using [Auth Helpers with the Next.js App Directory](/docs/guides/auth/auth-helpers/nextjs). @@ -914,3 +928,7 @@ import { Database } from '../database.types' const supabaseClient = useSupabaseClient() ``` + + + + diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx index 9094f5609a4..1d14e693b24 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx @@ -11,6 +11,20 @@ The `auth-helpers` package has been replaced with the `@supabase/ssr` package. W + + + + 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.
@@ -1312,3 +1326,7 @@ export default function() { ``` For an example of creating multiple Supabase clients, check [Singleton section](/docs/guides/auth/auth-helpers/nextjs#singleton) above. + + + + diff --git a/apps/docs/content/guides/auth/auth-helpers/remix.mdx b/apps/docs/content/guides/auth/auth-helpers/remix.mdx index 4871094a551..c7ed4671f46 100644 --- a/apps/docs/content/guides/auth/auth-helpers/remix.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/remix.mdx @@ -11,6 +11,20 @@ We generally recommend using the new `@supabase/ssr` package instead of `auth-he + + + + This submodule provides convenience helpers for implementing user authentication in Remix applications.
@@ -782,3 +796,7 @@ supabaseClient.auth.signUp({ }, }) ``` + + + + diff --git a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx index 37bf88cee01..d3b5bb74edb 100644 --- a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx @@ -11,6 +11,20 @@ We generally recommend using the new `@supabase/ssr` package instead of `auth-he + + + + This submodule provides convenience helpers for implementing user authentication in [SvelteKit](https://kit.svelte.dev/) applications. ## Configuration @@ -46,8 +60,6 @@ PUBLIC_SUPABASE_ANON_KEY=your-anon-key Create a new `hooks.server.js` file in the root of your project and populate with the following to retrieve the user session. -The session information from `getSession` is supplied to the Supabase client so it can retrieve the auth token. This is safe, since the auth token signature will be revalidated on the Auth server. But you shouldn't trust the unsigned data that is stored alongside the auth token: - ```js src/hooks.server.js @@ -63,15 +75,23 @@ export const handle = async ({ event, resolve }) => { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await supabase.auth.getUser() + if (error) { + return { session: null, user: null } + } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -102,15 +122,23 @@ export const handle: Handle = async ({ event, resolve }) => { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await supabase.auth.getUser() + if (error) { + return { session: null, user: null } + } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -189,17 +217,18 @@ In order to get the most out of TypeScript and it's intellisense, you should imp ```ts src/app.d.ts // src/app.d.ts -import { SupabaseClient, Session } from '@supabase/supabase-js' +import { SupabaseClient, Session, User } from '@supabase/supabase-js' import { Database } from './DatabaseDefinitions' declare global { namespace App { interface Locals { supabase: SupabaseClient - getSession(): Promise + safeGetSession(): Promise<{ session: Session | null; user: User | null }> } interface PageData { session: Session | null + user: User | null } // interface Error {} // interface Platform {} @@ -234,9 +263,12 @@ To make the session available across the UI, including pages and layouts, it is ```js src/routes/+layout.server.js // src/routes/+layout.server.js -export const load = async ({ locals: { getSession } }) => { +export const load = async ({ locals: { safeGetSession } }) => { + const { session, user } = await safeGetSession() + return { - session: await getSession(), + session, + user, } } ``` @@ -246,9 +278,12 @@ export const load = async ({ locals: { getSession } }) => { ```ts src/routes/+layout.server.ts // src/routes/+layout.server.ts -export const load = async ({ locals: { getSession } }) => { +export const load = async ({ locals: { safeGetSession } }) => { + const { session, user } = await safeGetSession() + return { - session: await getSession(), + session, + user, } } ``` @@ -284,6 +319,11 @@ export const load = async ({ fetch, data, depends }) => { serverSession: data.session, }) + /** + * It's fine to use `getSession` here, because on the client, `getSession` is + * safe, and on the server, it reads `session` from the `LayoutData`, which + * safely checked the session using `safeGetSession`. + */ const { data: { session }, } = await supabase.auth.getSession() @@ -312,6 +352,11 @@ export const load = async ({ fetch, data, depends }) => { serverSession: data.session, }) + /** + * It's fine to use `getSession` here, because on the client, `getSession` is + * safe, and on the server, it reads `session` from the `LayoutData`, which + * safely checked the session using `safeGetSession`. + */ const { data: { session }, } = await supabase.auth.getSession() @@ -532,8 +577,8 @@ Wrap an API Route to check that the user has a valid session. If they're not log // src/routes/api/protected-route/+server.ts import { json, error } from '@sveltejs/kit' -export const GET = async ({ locals: { supabase, getSession } }) => { - const session = await getSession() +export const GET = async ({ locals: { supabase, safeGetSession } }) => { + const { session } = await safeGetSession() if (!session) { // the user is not signed in throw error(401, { message: 'Unauthorized' }) @@ -555,8 +600,8 @@ Wrap an Action to check that the user has a valid session. If they're not logged import { error, fail } from '@sveltejs/kit' export const actions = { - createPost: async ({ request, locals: { supabase, getSession } }) => { - const session = await getSession() + createPost: async ({ request, locals: { supabase, safeGetSession } }) => { + const { session } = await safeGetSession() if (!session) { // the user is not signed in @@ -615,15 +660,21 @@ async function supabase({ event, resolve }) { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await event.locals.supabase.auth.getUser() + if (error) return { session: null, user: null } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -636,7 +687,7 @@ async function supabase({ event, resolve }) { async function authorization({ event, resolve }) { // protect requests to all routes that start with /protected-routes if (event.url.pathname.startsWith('/protected-routes') && event.request.method === 'GET') { - const session = await event.locals.getSession() + const { session } = await event.locals.safeGetSession() if (!session) { // the user is not signed in redirect(303, '/') @@ -645,7 +696,7 @@ async function authorization({ event, resolve }) { // protect POST requests to all routes that start with /protected-posts if (event.url.pathname.startsWith('/protected-posts') && event.request.method === 'POST') { - const session = await event.locals.getSession() + const { session } = await event.locals.safeGetSession() if (!session) { // the user is not signed in throw error(303, '/') @@ -677,15 +728,21 @@ async function supabase({ event, resolve }) { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await event.locals.supabase.auth.getUser() + if (error) return { session: null, user: null } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -698,7 +755,7 @@ async function supabase({ event, resolve }) { async function authorization({ event, resolve }) { // protect requests to all routes that start with /protected-routes if (event.url.pathname.startsWith('/protected-routes') && event.request.method === 'GET') { - const session = await event.locals.getSession() + const { session } = await event.locals.safeGetSession() if (!session) { // the user is not signed in redirect(303, '/') @@ -707,7 +764,7 @@ async function authorization({ event, resolve }) { // protect POST requests to all routes that start with /protected-posts if (event.url.pathname.startsWith('/protected-posts') && event.request.method === 'POST') { - const session = await event.locals.getSession() + const { session } = await event.locals.safeGetSession() if (!session) { // the user is not signed in throw error(303, '/') @@ -896,15 +953,21 @@ export const handle: Handle = async ({ event, resolve }) => { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await event.locals.supabase.auth.getUser() + if (error) return { session: null, user: null } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -1055,17 +1118,18 @@ declare namespace App { ```ts src/app.d.ts // src/app.d.ts -import { SupabaseClient, Session } from '@supabase/supabase-js' +import { SupabaseClient, Session, User } from '@supabase/supabase-js' import { Database } from './DatabaseDefinitions' declare global { namespace App { interface Locals { supabase: SupabaseClient - getSession(): Promise + safeGetSession(): Promise<{ session: Session | null; user: User | null }> } interface PageData { session: Session | null + user: User | null } // interface Error {} // interface Platform {} @@ -1196,7 +1260,7 @@ import type { RequestHandler } from './$types' import { json, error } from '@sveltejs/kit' export const GET: RequestHandler = async ({ locals: { supabase, getSession } }) => { - const session = await getSession() + const { session } = await getSession() if (!session) { // the user is not signed in throw error(401, { message: 'Unauthorized' }) @@ -1966,3 +2030,7 @@ export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient - [Auth Helpers Source code](https://github.com/supabase/auth-helpers) - [SvelteKit example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit) + + + + diff --git a/apps/docs/content/guides/auth/server-side/creating-a-client.mdx b/apps/docs/content/guides/auth/server-side/creating-a-client.mdx index b8917844105..cde78fb8854 100644 --- a/apps/docs/content/guides/auth/server-side/creating-a-client.mdx +++ b/apps/docs/content/guides/auth/server-side/creating-a-client.mdx @@ -429,12 +429,6 @@ export default function Index () { Creating a Supabase client with the `ssr` package automatically configures it to use Cookies. This means your user's session is available throughout the entire SvelteKit stack - page, layout, server, hooks. - - -Beware when accessing the session object on the server, because it is not revalidated on every request from the client. That means the sender can tamper with unencoded data in the session object. If you need to verify the integrity of user data for server logic, call `auth.getUser` instead, which will query the Supabase Auth server for trusted user data. - - - { }) /** - * a little helper that is written for convenience so that instead - * of calling `const { data: { session } } = await supabase.auth.getSession()` - * you just call this `await getSession()` + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await event.locals.supabase.auth.getUser() + if (error) { + return { session: null, user: null } + } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -528,6 +530,11 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { }, }) + /** + * It's fine to use `getSession` here, because on the client, `getSession` is + * safe, and on the server, it reads `session` from the `LayoutData`, which + * safely checked the session using `safeGetSession`. + */ const { data: { session }, } = await supabase.auth.getSession() @@ -543,9 +550,12 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { ```ts +layout.server.ts import type { LayoutServerLoad } from './$types' -export const load: LayoutServerLoad = async ({ locals: { getSession } }) => { +export const load: LayoutServerLoad = async ({ locals: { safeGetSession } }) => { + const { session, user } = await safeGetSession() + return { - session: await getSession(), + session, + user, } } ``` diff --git a/apps/docs/content/guides/auth/server-side/nextjs.mdx b/apps/docs/content/guides/auth/server-side/nextjs.mdx index f90f3c2c781..c693e2c7e48 100644 --- a/apps/docs/content/guides/auth/server-side/nextjs.mdx +++ b/apps/docs/content/guides/auth/server-side/nextjs.mdx @@ -812,11 +812,11 @@ Since this is an API route, use the Supabase client from `@/utils/supabase/api.t -```ts pages/api/auth/confirm.tsx +```ts pages/api/auth/confirm.ts import { type EmailOtpType } from '@supabase/supabase-js' import type { NextApiRequest, NextApiResponse } from 'next' -import { createClient } from '@/utils/supabase/api' +import createClient from '@/utils/supabase/api' function stringOrFirstString(item: string | string[] | undefined) { return Array.isArray(item) ? item[0] : item @@ -869,7 +869,7 @@ export default function ErrorPage() { If you use dynamic server-side rendering, you can serve a page to authenticated users only by checking for the user data in `getServerSideProps`. Unauthenticated users will be redirected to the home page. -Since you're calling Supabse from `getServerSideProps`, use the client from `@/utils/supabase/server-props.ts`. +Since you're calling Supabase from `getServerSideProps`, use the client from `@/utils/supabase/server-props.ts`. diff --git a/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx b/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx index bc69e411514..1b8ca766dfc 100644 --- a/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx +++ b/apps/docs/content/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx @@ -231,7 +231,7 @@ await supabase.auth.signInWithOAuth({ -In the server, you need to handle the redirect to the SSO provider's authentication endpoint. The `signInWithOAuth` method returns the endpoint URL, which you can redirect to. +In the server, you need to handle the redirect to the OAuth provider's authentication endpoint. The `signInWithOAuth` method returns the endpoint URL, which you can redirect to. ```js const { data, error } = await supabase.auth.signInWithOAuth({ diff --git a/apps/docs/content/guides/cli/local-development.mdx b/apps/docs/content/guides/cli/local-development.mdx index 7bfc591f10f..5e7ff222041 100644 --- a/apps/docs/content/guides/cli/local-development.mdx +++ b/apps/docs/content/guides/cli/local-development.mdx @@ -461,7 +461,17 @@ The buckets and objects themselves are rows in the storage schema so they won't ### Local logging -Local logs rely on the Supabase Analytics Server, and are available in the Studio automatically. +Local logs rely on the Supabase Analytics Server, and are not enabled by default. To enable this, edit your `supabase/config.toml` file and set `enabled` to `true`. + +```bash supabase/config.toml +[analytics] +# Set enabled to true to see logs in the Logs Explorer +enabled = true +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" +``` diff --git a/apps/docs/content/guides/database/connecting-to-postgres.mdx b/apps/docs/content/guides/database/connecting-to-postgres.mdx index 140893211c5..c388e1a0720 100644 --- a/apps/docs/content/guides/database/connecting-to-postgres.mdx +++ b/apps/docs/content/guides/database/connecting-to-postgres.mdx @@ -374,3 +374,36 @@ Connection pooler logs are found [here](https://supabase.com/dashboard/project/_ - Terminating with reason :client_termination when state was :busy This error happens when the client terminates the connection before the connection with the database is completed. + +## Finding your database hostname + +Your database’s hostname is crucial for establishing a direct connection. It resolves to the underlying IP address of your database. To find your hostname, navigate to your [Database Settings](/dashboard/project/_/settings/database). + +Note that the pooler (connection pooler) has a different IP than your database. To reveal the database host and direct connection string, hide the pooler connection string. + +Example hostname: `db..supabase.co` + +## Managing your IP address + +To determine your current IP address, you can use an IP address [lookup website](https://whatismyipaddress.com/hostname-ip) or the terminal command: + +```shell +nslookup db..supabase.co +``` + +This command queries the domain name servers to find the IP address of the given hostname. + +Example IPv6 Address: `2a05:d014:1c06:5f0c:d7a9:8616:bee2:30df` + +### IPv6 address + +Upon project creation, a static IPv6 address is assigned. This address might change when: + +- A project is paused or resumed. +- The database is upgraded. + +### IPv4 address + +Opting for the static [IPv4 add-on](https://supabase.com/docs/guides/platform/ipv4-address) provides a more stable connection address. The IPv4 address remains constant unless the project is paused or resumed. + +Unlike the IPv6 address, upgrading your database doesn't affect the IPv4 address. diff --git a/apps/docs/content/guides/database/extensions/pg_cron.mdx b/apps/docs/content/guides/database/extensions/pg_cron.mdx index 7aca787c7cd..7dd38aaafac 100644 --- a/apps/docs/content/guides/database/extensions/pg_cron.mdx +++ b/apps/docs/content/guides/database/extensions/pg_cron.mdx @@ -62,11 +62,13 @@ The schedule uses the standard cron syntax, in which \* means "run every time pe * * * * * ``` -You can use [crontab.guru](https://crontab.guru/) to help validate your cron schedules. +You can use `[1-59] seconds` as the cron syntax to schedule sub-minute jobs. This is available on `pg_cron` v1.5.0+; upgrade your existing Supabase project to use this syntax. + +Head over to [crontab.guru](https://crontab.guru/) to validate your cron schedules. ### Scheduling system maintenance -Be extremely careful when setting up pg_cron jobs for system maintenance tasks as they can have unintended consequences. For instance, scheduling a command to terminate idle connections with `pg_terminate_backend(pid)` can disrupt critical background processes like nightly backups. Often, there is an existing Postgres setting e.g. `idle_session_timeout` that can perform these common maintenance tasks without the risk. +Be extremely careful when setting up `pg_cron` jobs for system maintenance tasks as they can have unintended consequences. For instance, scheduling a command to terminate idle connections with `pg_terminate_backend(pid)` can disrupt critical background processes like nightly backups. Often, there is an existing Postgres setting e.g. `idle_session_timeout` that can perform these common maintenance tasks without the risk. Reach out to [Supabase Support](https://supabase.com/support) if you're unsure if that applies to your use case. @@ -74,7 +76,7 @@ Reach out to [Supabase Support](https://supabase.com/support) if you're unsure i ### Delete data every week -Delete old data on Saturday at 3:30am (GMT): +Delete old data every Saturday at 3:30am (GMT): ```sql select cron.schedule ( @@ -86,21 +88,35 @@ select cron.schedule ( ### Run a vacuum every day -Vacuum every day at 3:00am (GMT) +Vacuum every day at 3:00am (GMT): ```sql select cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM'); ``` -### Invoke Supabase Edge Function every minute +### Call a database function every 5 minutes -Make a POST request to a Supabase Edge Function every minute. Note: this requires the [`pg_net` extension](/docs/guides/database/extensions/pgnet) to be enabled. +Create a [`hello_world()`](https://supabase.com/docs/guides/database/functions?language=sql#simple-functions) database function and then call it every 5 minutes: + +```sql +select cron.schedule('call-db-function', '*/5 * * * *', 'CALL hello_world()'); +``` + +### Invoke Supabase Edge Function every 30 seconds + + + +This requires `pg_cron` v1.5.0+ and the [`pg_net` extension](/docs/guides/database/extensions/pgnet) to be enabled. + + + +Make a POST request to a Supabase Edge Function every 30 seconds: ```sql select cron.schedule( - 'invoke-function-every-minute', - '* * * * *', -- every minute + 'invoke-function-every-half-minute', + '30 seconds', $$ select net.http_post( @@ -164,4 +180,4 @@ The records in cron.job_run_details are not cleaned automatically which will tak ## Resources -- [pg_cron GitHub Repository](https://github.com/citusdata/pg_cron) +- [`pg_cron` GitHub Repository](https://github.com/citusdata/pg_cron) diff --git a/apps/docs/content/guides/database/extensions/pgaudit.mdx b/apps/docs/content/guides/database/extensions/pgaudit.mdx index 2d9f5a2afc9..e653eccd317 100644 --- a/apps/docs/content/guides/database/extensions/pgaudit.mdx +++ b/apps/docs/content/guides/database/extensions/pgaudit.mdx @@ -4,7 +4,7 @@ title: 'PGAudit: Postgres Auditing' description: 'Session and object auditing via PostgreSQL standard logging' --- -[PGAudit](https://www.pgaudit.org) is a PostgreSQL extension that extends PostgreSQL's built-in logging abilities. It can be used to selectively track activities within your database. +[PGAudit](https://www.pgaudit.org) extends Postgres's built-in logging abilities. It can be used to selectively track activities within your database. This helps you with: @@ -12,7 +12,7 @@ This helps you with: - **Security**: Detecting suspicious database activity - **Troubleshooting**: Identifying and fixing database issues -## Enable the Extension +## Enable the extension -{/* prettier-ignore */} ```sql -- Enable the "pgaudit" extension create extension pgaudit; @@ -42,20 +41,20 @@ drop extension if exists pgaudit; -## Configure the Extension +## Configure the extension -PGAudit can be configured with multiple different levels of precision. +PGAudit can be configured with different levels of precision. -**PGAudit Logging Precision:** +**PGAudit logging precision:** -- **[Session](#session-logging):** Logs activity within a connection, such as a [PSQL](https://supabase.com/docs/guides/database/connecting-to-postgres#connecting-with-psql) connection. -- **[User](#user-logging):** Logs activity by a particular database user (e.g., anon or postgres). +- **[Session](#session-logging):** Logs activity within a connection, such as a [psql](https://supabase.com/docs/guides/database/connecting-to-postgres#connecting-with-psql) connection. +- **[User](#user-logging):** Logs activity by a particular database user (for example, anon or postgres). - **[Global](#global-logging):** Logs activity across the entire database. -- **[Object](#object-mode-settings):** Logs events related to specific database objects (for example, the auth.users table). +- **[Object](#object-logging):** Logs events related to specific database objects (for example, the auth.users table). -Although Session, User, and Global modes differ in their precision, they are all considered variants of **Session Mode** and are configured with the same input categories. +Although Session, User, and Global modes differ in their precision, they're all considered variants of **Session Mode** and are configured with the same input categories. -### Session Mode Categories +### Session mode categories These modes can monitor predefined categories of database operations: @@ -69,7 +68,7 @@ These modes can monitor predefined categories of database operations: | misc | Less common commands (FETCH, CHECKPOINT) | Captures obscure actions for deeper analysis if needed. | | all | Everything above | Comprehensive logging for complete audit trails. | -Below is a limited example of how to assign pgaudit to monitor specific categories. +Below is a limited example of how to assign PGAudit to monitor specific categories. ```sql -- log all CREATE, ALTER, and DROP events @@ -82,24 +81,24 @@ Below is a limited example of how to assign pgaudit to monitor specific categori ... pgaudit.log = 'none'; ``` -### Session Logging +### Session logging -When you are connecting in a session environment, such as a PSQL connection, you can configure pgaudit to record events initiated within the session. +When you are connecting in a session environment, such as a [psql](https://supabase.com/docs/guides/database/connecting-to-postgres#connecting-with-psql) connection, you can configure PGAudit to record events initiated within the session. -The [Dashboard](https://supabase.com/dashboard/project/_) is a transactional environment and will not sustain a session. +The [Dashboard](https://supabase.com/dashboard/project/_) is a transactional environment and won't sustain a session. -Inside a session, by default, pgaudit will log nothing: +Inside a session, by default, PGAudit will log nothing: ```sql -- returns 'none' show pgaudit.log; ``` -In the session, you can `SET` the `pgaudit.log` variable to record events: +In the session, you can `set` the `pgaudit.log` variable to record events: ```sql -- log CREATE, ALTER, and DROP events @@ -112,7 +111,7 @@ set pgaudit.log = 'read, ddl'; set pgaudit.log = 'none'; ``` -### User Logging +### User logging There are some cases where you may want to monitor a database user's actions. For instance, let's say you connected your database to [Zapier](https://supabase.com/partners/integrations/zapier) and created a custom role for it to use: @@ -130,25 +129,26 @@ To remove the settings, execute the following code: ```sql -- disables role's log -alter role "zapier" set pgaudit.log TO 'none'; +alter role "zapier" set pgaudit.log to 'none'; -- check to make sure the changes are finalized: -select rolname, +select + rolname, rolconfig from pg_roles where rolname = 'zapier'; -- should return a rolconfig path with "pgaudit.log=none" present ``` -### Global Logging +### Global logging -Use global logging sparingly as it can generate many logs and make it difficult to find important events. Consider limiting the scope of what is logged by using user or object logging where possible. +Use global logging cautiously. It can generate many logs and make it difficult to find important events. Consider limiting the scope of what is logged by using session, user, or object logging where possible. -The below SQL configures pgaudit to record all events associated with the "postgres" role. Since postgres has extensive privileges, this effectively monitors all database activity. +The below SQL configures PGAudit to record all events associated with the "postgres" role. Since it has extensive privileges, this effectively monitors all database activity. ```sql alter role "postgres" set pgaudit.log to 'all'; @@ -171,35 +171,31 @@ To remove the settings, execute the following code: alter role "postgres" set pgaudit.log to 'none'; ``` -## Object Mode Settings +### Object logging -Assigning a role to pgaudit will result in the logging of **any actions** that role is **capable** of performing, _regardless of who or what actually initiated the event_. - -### Object Logging - -To fine-tune what pgaudit will record, you must create a custom database role with limited permissions: +To fine-tune what object events PGAudit will record, you must create a custom database role with limited permissions: ```sql create role "some_audit_role" noinherit; ``` -No other Postgres user can assume or login via this role. It solely exists to securely define what pgaudit will record. +No other Postgres user can assume or login via this role. It solely exists to securely define what PGAudit will record. -Once the role is created, you can direct pgaudit to log by assigning it to the `pgaudit.role` variable: +Once the role is created, you can direct PGAudit to log by assigning it to the `pgaudit.role` variable: ```sql alter role "postgres" set pgaudit.role to 'some_audit_role'; ``` -You can then assign the role to monitor only approved events, such as `select` statements that include a specific table: +You can then assign the role to monitor only approved object events, such as `select` statements that include a specific table: ```sql grant select on random_table to "some_audit_role"; ``` -With this privilege granted, pgaudit will record all select statements against the `random_table`. Note, that this does include joins that feature the table, too. All assignignable priveleges can be viewed in the [PostgreSQL documentation](https://www.postgresql.org/docs/current/ddl-priv.html). +With this privilege granted, PGAudit will record all select statements that reference the `random_table`, regardless of _who_ or _what_ actually initiated the event. All assignable privileges can be viewed in the [Postgres documentation](https://www.postgresql.org/docs/current/ddl-priv.html). -If you would no longer like to use object logging, you will need to unnasign the `pgaudit.role` variable: +If you would no longer like to use object logging, you will need to unassign the `pgaudit.role` variable: ```sql -- change pgaudit.role to no longer reference some_audit_role @@ -214,27 +210,21 @@ where rolname = 'postgres'; -- should return a rolconfig path with "pgaudit.role=" ``` -If you are no longer using a `ROLE`, it is best to `DROP`it: - -```sql -drop role "some_audit_role"; -``` - ## Interpreting Audit Logs -pgaudit was designed for storing logs as CSV files with the following headers: +PGAudit was designed for storing logs as CSV files with the following headers: -> Referenced from the [pgaudit official docs](https://github.com/pgaudit/pgaudit/blob/master/README.md#format) +> Referenced from the [PGAudit official docs](https://github.com/pgaudit/pgaudit/blob/master/README.md#format) | header | Description | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | AUDIT_TYPE | SESSION or OBJECT | | STATEMENT_ID | Unique statement ID for this session. Sequential even if some statements are not logged. | | SUBSTATEMENT_ID | Sequential ID for each sub-statement within the main statement. Continuous even if some are not logged. | -| CLASS | e.g., READ, ROLE (see pgaudit.log). | -| COMMAND | e.g., ALTER TABLE, SELECT. | +| CLASS | ..., READ, ROLE (see pgaudit.log). | +| COMMAND | ..., ALTER TABLE, SELECT. | | OBJECT_TYPE | TABLE, INDEX, VIEW, etc. Available for SELECT, DML, and most DDL statements. | -| OBJECT_NAME | The fully qualified object name (e.g., public.account). Available for SELECT, DML, and most DDL. | +| OBJECT_NAME | The fully qualified object name (for example, public.account). Available for SELECT, DML, and most DDL. | | STATEMENT | Statement executed on the backend. | | PARAMETER | If pgaudit.log_parameter is set, this field contains the statement parameters as quoted CSV, or \. Otherwise, it's \. | @@ -258,9 +248,9 @@ Generates the following log in the [Dashboard's Postgres Logs](https://supabase. ); ``` -## Finding and Filtering Audit Logs +## Finding and filtering audit logs -Logs generated by pgaudit can be found in [Postgres Logs](https://supabase.com/dashboard/project/_/logs/postgres-logs?s=AUDIT). To find a specific log, you can use the log explorer. Below is a basic example to extract logs referencing `CREATE TABLE` events +Logs generated by PGAudit can be found in [Postgres Logs](https://supabase.com/dashboard/project/_/logs/postgres-logs?s=AUDIT). To find a specific log, you can use the log explorer. Below is a basic example to extract logs referencing `CREATE TABLE` events ```sql select @@ -275,7 +265,7 @@ order by timestamp desc limit 100; ``` -## Practical Examples +## Practical examples ### Monitoring API events @@ -296,9 +286,9 @@ alter role "authenticator" set pgaudit.log to 'write'; -- alter role "service_role" set pgaudit.log TO 'write'; ``` -### Monitoring the `auth.users` Table +### Monitoring the `auth.users` table -In the worst case scenario, where a privileged roles' password is exposed, you can use pgaudit to monitor if the `auth.users` table was targeted. It should be stated that API requests are already monitored in the [API Edge Network](https://supabase.com/dashboard/project/_/logs/edge-logs) and this is more about providing greater clarity about what is happening at the database level. +In the worst case scenario, where a privileged roles' password is exposed, you can use PGAudit to monitor if the `auth.users` table was targeted. It should be stated that API requests are already monitored in the [API Edge Network](https://supabase.com/dashboard/project/_/logs/edge-logs) and this is more about providing greater clarity about what is happening at the database level. Logging `auth.user` should be done in Object Mode and requires a custom role: @@ -312,18 +302,17 @@ grant delete on auth.users to "auth_auditor"; -- assign auth_auditor to pgaudit.role alter role "postgres" set pgaudit.role to 'auth_auditor'; - ``` -With the above code, any query involving reading or deleting the auth.users email column will be logged. +With the above code, any query involving reading or deleting from the auth.users table will be logged. -## Best Practices +## Best practices -### Over-logging: Help! Too many logs! +### Disabling excess logging -pgaudit, if not configured mindfully, can log all database events, including background tasks. This can generate an undesirablely large amount of logs in a few hours. +PGAudit, if not configured mindfully, can log all database events, including background tasks. This can generate an undesirably large amount of logs in a few hours. -The first step to solve this problem is to identify which database users pgaudit is observing: +The first step to solve this problem is to identify which database users PGAudit is observing: ```sql -- find all users monitored by pgaudit @@ -340,7 +329,7 @@ where ); ``` -To prevent pgaudit from monitoring the problematic roles, you'll want to change their `pgaudit.log` values to `none` and `pgaudit.role` values to `empty quotes ''` +To prevent PGAudit from monitoring the problematic roles, you'll want to change their `pgaudit.log` values to `none` and `pgaudit.role` values to `empty quotes ''` ```sql -- Use to disable object level logging @@ -352,7 +341,7 @@ To prevent pgaudit from monitoring the problematic roles, you'll want to change ## FAQ -#### How can I use pgaudit to debug database functions? +#### Can I use PGAudit to debug database functions? Technically yes, but it is not the best approach. It is better to check out our [function debugging guide](https://supabase.com/docs/guides/database/functions#general-logging) instead. @@ -362,7 +351,7 @@ In the [Logs Dashboard](https://supabase.com/dashboard/project/_/logs/postgres-l #### Can I log observed table rows? -By default, pgaudit records queries, but not the returned rows. You can modify this behavior with the `pgaudit.log_rows` variable: +By default, PGAudit records queries, but not the returned rows. You can modify this behavior with the `pgaudit.log_rows` variable: ```sql --enable @@ -372,31 +361,31 @@ alter role "postgres" set pgaudit.log_rows to 'on'; alter role "postgres" set pgaudit.log_rows to 'off'; ``` -You should not do this unless you are _absolutely_ certain it is necessary for your use case. It can expose sensitive values to your logs that ideally should not be preserved. Furthermore, if done in excess, it can noticably reduce database performance. +You should not do this unless you are _absolutely_ certain it is necessary for your use case. It can expose sensitive values to your logs that ideally should not be preserved. Furthermore, if done in excess, it can noticeably reduce database performance. #### Can I log function parameters? -We don't currently support configuring pgaudit.log_parameter because it may log secrets in encrypted columns if you are using [pgsodium](https://supabase.com/docs/guides/database/extensions/pgsodium) or[Vault](https://supabase.com/docs/guides/database/vault). +We don't currently support configuring `pgaudit.log_parameter` because it may log secrets in encrypted columns if you are using [pgsodium](https://supabase.com/docs/guides/database/extensions/pgsodium) or[Vault](https://supabase.com/docs/guides/database/vault). You can upvote this [feature request](https://github.com/orgs/supabase/discussions/20183) with your use-case if you'd like this restriction lifted. -#### Why do the official pgaudit docs differ from the Supabase one? +#### Does PGAudit support system wide configurations? -pgaudit allows settings to be applied at 3 different database scopes: +PGAudit allows settings to be applied to 3 different database scopes: -| Scope | Definition | Configuration File/Command | +| Scope | Description | Configuration File/Command | | -------- | ------------------ | -------------------------- | | System | Entire server | ALTER SYSTEM commands | | Database | Specific database | ALTER DATABASE commands | | Role | Specific user/role | ALTER ROLE commands | -Supabase limits full privileges for file system and database variables, meaning pgaudit modifications can only occur at the ROLE level. Assigning pgaudit to the 'postgres' role provides it with the role's database visibility, allowing `ROLE` level adjustments a practical alternative to DATABASE/SYSTEM level configurations. +Supabase limits full privileges for file system and database variables, meaning PGAudit modifications can only occur at the role level. Assigning PGAudit to the 'postgres' role grants it nearly complete visibility into the database, making role-level adjustments a practical alternative to configuring at the database or system level. -pgaudit's [official documentation](https://www.pgaudit.org) focuses on system and database level configs, but its docs officially supports `ROLE` level configs, too: +PGAudit's [official documentation](https://www.pgaudit.org) focuses on system and database level configs, but its docs officially supports role level configs, too. ## Resources -- Official [`PGAudit` documentation](https://www.pgaudit.org) +- [Official `PGAudit` documentation](https://www.pgaudit.org) - [Database Function Logging](https://supabase.com/docs/guides/database/functions#general-logging) - [Supabase Logging](https://supabase.com/docs/guides/platform/logs) - [Self-Hosting Logs](https://supabase.com/docs/reference/self-hosting-analytics/introduction) diff --git a/apps/docs/content/guides/database/functions.mdx b/apps/docs/content/guides/database/functions.mdx index c3f9ecb900c..cdb910df794 100644 --- a/apps/docs/content/guides/database/functions.mdx +++ b/apps/docs/content/guides/database/functions.mdx @@ -347,7 +347,7 @@ Good targets to log include: #### General logging -To create custom logs in the [Dashboard's Postgres Logs](/apps/docs/public/img/database/postgres-logs.png), you can use the `raise` keyword. By default, there are 3 observed severity levels: +To create custom logs in the [Dashboard's Postgres Logs](https://supabase.com/dashboard/project/_/logs/postgres-logs), you can use the `raise` keyword. By default, there are 3 observed severity levels: - `log` - `warning` diff --git a/apps/docs/content/guides/functions/debugging.mdx b/apps/docs/content/guides/functions/debugging.mdx index ce5d0fd1488..dd609593279 100644 --- a/apps/docs/content/guides/functions/debugging.mdx +++ b/apps/docs/content/guides/functions/debugging.mdx @@ -177,6 +177,6 @@ import { Sheets } from 'npm:@googleapis/sheets' - Outgoing connections to ports `25` and `587` are not allowed. - Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`). - Deno and Node file system APIs are not available. -- Memory limit for the function: 150 MB (heap) + 150 MB (external - array buffers/ WASM) +- Memory limit for the function: 256MB - Wall clock limit: 400 s - CPU Time: 2 s diff --git a/apps/docs/content/guides/functions/examples/cloudflare-turnstile.mdx b/apps/docs/content/guides/functions/examples/cloudflare-turnstile.mdx index 2e6b1bd1355..702f4871bcf 100644 --- a/apps/docs/content/guides/functions/examples/cloudflare-turnstile.mdx +++ b/apps/docs/content/guides/functions/examples/cloudflare-turnstile.mdx @@ -78,7 +78,7 @@ Deno.serve(async (req) => { ```bash supabase functions deploy cloudflare-turnstile -supabase secrets set CLOUDFLARE_TURNSTILE_SECRET_KEY=your_secret_key +supabase secrets set CLOUDFLARE_SECRET_KEY=your_secret_key ``` ## Invoke the function from your site diff --git a/apps/docs/content/guides/getting-started/quickstarts/flutter.mdx b/apps/docs/content/guides/getting-started/quickstarts/flutter.mdx index dd94b5b841c..de0e8ddb7bd 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/flutter.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/flutter.mdx @@ -117,7 +117,7 @@ hideToc: true ```dart lib/main.dart class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx index fd508ca38eb..5e5e8516b83 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx @@ -171,6 +171,6 @@ hideToc: true ## Next steps -- Set up [Auth](/docs/guides/auth/server-side/overview) for your app +- Set up [Auth](/docs/guides/auth) for your app - [Insert more data](/docs/guides/database/import-data) into your database - Upload and serve static files using [Storage](/docs/guides/storage) diff --git a/apps/docs/content/guides/getting-started/quickstarts/reactjs.mdx b/apps/docs/content/guides/getting-started/quickstarts/reactjs.mdx index 65e8544dc58..d8d185ce0f1 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/reactjs.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/reactjs.mdx @@ -139,6 +139,6 @@ hideToc: true ## Next steps -- Set up [Auth](/docs/guides/auth/server-side/overview) for your app +- Set up [Auth](/docs/guides/auth) for your app - [Insert more data](/docs/guides/database/import-data) into your database - Upload and serve static files using [Storage](/docs/guides/storage) diff --git a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx index 2c98a7050a7..2082280150e 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx @@ -161,6 +161,6 @@ hideToc: true ## Next steps -- Set up [Auth](/docs/guides/auth/server-side/overview) for your app +- Set up [Auth](/docs/guides/auth) for your app - [Insert more data](/docs/guides/database/import-data) into your database - Upload and serve static files using [Storage](/docs/guides/storage) diff --git a/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx b/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx index b6e24481a01..21b134ede11 100644 --- a/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx +++ b/apps/docs/content/guides/getting-started/tutorials/with-sveltekit.mdx @@ -85,13 +85,23 @@ export const handle: Handle = async ({ event, resolve }) => { }) /** - * A convenience helper so we can just call await getSession() instead const { data: { session } } = await supabase.auth.getSession() + * Unlike `supabase.auth.getSession`, which is unsafe on the server because it + * doesn't validate the JWT, this function validates the JWT by first calling + * `getUser` and aborts early if the JWT signature is invalid. */ - event.locals.getSession = async () => { + event.locals.safeGetSession = async () => { + const { + data: { user }, + error, + } = await supabase.auth.getUser() + if (error) { + return { session: null, user: null } + } + const { data: { session }, } = await event.locals.supabase.auth.getSession() - return session + return { session, user } } return resolve(event, { @@ -104,9 +114,7 @@ export const handle: Handle = async ({ event, resolve }) => { -In this case, the session information from `getSession` is supplied to the Supabase client so it can retrieve the auth token. This is safe, since the auth token signature will be revalidated on the Auth server. But you shouldn't trust the unsigned data that is stored alongside the JWT. - -If you are using TypeScript the compiler might complain about `event.locals.supabase` and `event.locals.getSession`, this can be fixed by updating your `src/app.d.ts` with the content below: +If you are using TypeScript the compiler might complain about `event.locals.supabase` and `event.locals.safeGetSession`, this can be fixed by updating your `src/app.d.ts` with the content below: ```ts src/app.d.ts // src/app.d.ts @@ -117,10 +125,11 @@ declare global { namespace App { interface Locals { supabase: SupabaseClient - getSession(): Promise + safeGetSession(): Promise<{ session: Session | null; user: User | null }> } interface PageData { session: Session | null + user: User | null } // interface Error {} // interface Platform {} @@ -134,9 +143,12 @@ Create a new `src/routes/+layout.server.ts` file to handle the session on the se // src/routes/+layout.server.ts import type { LayoutServerLoad } from './$types' -export const load: LayoutServerLoad = async ({ locals: { getSession } }) => { +export const load: LayoutServerLoad = async ({ locals: { safeGetSession } }) => { + const { session, user } = await safeGetSession() + return { - session: await getSession(), + session, + user, } } ``` @@ -170,6 +182,11 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { }, }) + /** + * It's fine to use `getSession` here, because on the client, `getSession` is + * safe, and on the server, it reads `session` from the `LayoutData`, which + * safely checked the session using `safeGetSession`. + */ const { data: { session }, } = await supabase.auth.getSession() @@ -259,8 +276,8 @@ Create a `src/routes/+page.server.ts` file that will return our website URL to b import { redirect } from '@sveltejs/kit' import type { PageServerLoad } from './$types' -export const load: PageServerLoad = async ({ url, locals: { getSession } }) => { - const session = await getSession() +export const load: PageServerLoad = async ({ url, locals: { safeGetSession } }) => { + const { session } = await safeGetSession() // if the user is already logged in return them to the account page if (session) { @@ -419,8 +436,8 @@ and handle all our form actions through the `actions` object. import { fail, redirect } from '@sveltejs/kit' import type { Actions, PageServerLoad } from './$types' -export const load: PageServerLoad = async ({ locals: { supabase, getSession } }) => { - const session = await getSession() +export const load: PageServerLoad = async ({ locals: { supabase, safeGetSession } }) => { + const { session } = await safeGetSession() if (!session) { throw redirect(303, '/') @@ -436,14 +453,14 @@ export const load: PageServerLoad = async ({ locals: { supabase, getSession } }) } export const actions: Actions = { - update: async ({ request, locals: { supabase, getSession } }) => { + update: async ({ request, locals: { supabase, safeGetSession } }) => { const formData = await request.formData() const fullName = formData.get('fullName') as string const username = formData.get('username') as string const website = formData.get('website') as string const avatarUrl = formData.get('avatarUrl') as string - const session = await getSession() + const { session } = await safeGetSession() const { error } = await supabase.from('profiles').upsert({ id: session?.user.id, @@ -470,8 +487,8 @@ export const actions: Actions = { avatarUrl, } }, - signout: async ({ locals: { supabase, getSession } }) => { - const session = await getSession() + signout: async ({ locals: { supabase, safeGetSession } }) => { + const { session } = await safeGetSession() if (session) { await supabase.auth.signOut() throw redirect(303, '/') diff --git a/apps/docs/content/guides/platform/billing-faq.mdx b/apps/docs/content/guides/platform/billing-faq.mdx index 6616ce86ccc..4c29c53557b 100644 --- a/apps/docs/content/guides/platform/billing-faq.mdx +++ b/apps/docs/content/guides/platform/billing-faq.mdx @@ -64,7 +64,7 @@ Read more on [how billing for compute works](https://supabase.com/docs/guides/pl #### What is unified egress and how is it billed? -Unified egress refers to the total egress quota available to each organization. This quota can be utilized for various purposes such as Storage, Runtime, Auth, Functions, and Database. Each plan includes a specific egress quota, and any additional usage beyond that quota is billed accordingly. +Unified egress refers to the total egress quota available to each organization. This quota can be utilized for various purposes such as Storage, Realtime, Auth, Functions, Supavisor and Database. Each plan includes a specific egress quota, and any additional usage beyond that quota is billed accordingly. To learn more about unified egress and its details, please refer to the information provided [here](https://supabase.com/docs/guides/platform/org-based-billing#:~:text=running%20any%20projects.-,Unified%20egress,-%23). diff --git a/apps/docs/content/guides/platform/branching.mdx b/apps/docs/content/guides/platform/branching.mdx index c4a50238e0a..a3f451240df 100644 --- a/apps/docs/content/guides/platform/branching.mdx +++ b/apps/docs/content/guides/platform/branching.mdx @@ -18,15 +18,6 @@ When you're ready to ship your changes, merge your branch to update your product If you understand Git, you already understand Supabase Branching. - - -Branching will move to Public Beta in future, but only available for Pro plan and above. - - - ## How branching works Supabase Branching works with Git. You can test changes in a separate, temporary environment without affecting your production setup. When you're ready to ship your changes, merge your branch to update your production instance with the new changes. diff --git a/apps/docs/content/guides/platform/compute-add-ons.mdx b/apps/docs/content/guides/platform/compute-add-ons.mdx index 1ec47d69a49..a8a2e3ad4e6 100644 --- a/apps/docs/content/guides/platform/compute-add-ons.mdx +++ b/apps/docs/content/guides/platform/compute-add-ons.mdx @@ -6,18 +6,25 @@ description: "Learn about your project's instance and additional add-ons." Every project on the Supabase Platform comes with its own dedicated Postgres instance running inside a virtual machine (VM). The following table describes the base instance with additional compute add-ons available if you need extra performance when scaling up Supabase. -| Plan | Hourly Price USD | Monthly Price USD | CPU | Memory | Connections: Direct | Connections: Pooler | Recommended Maximum DB Size | -| ------ | ---------------- | ----------------- | ----------------------- | ------ | ------------------- | ------------------- | --------------------------- | -| Micro | $0.01344 | ~$10 | 2-core ARM (shared) | 1 GB | 60 | 200 | 10GB | -| Small | $0.0206 | ~$15 | 2-core ARM (shared) | 2 GB | 90 | 200 | 50GB | -| Medium | $0.0822 | ~$60 | 2-core ARM (shared) | 4 GB | 120 | 200 | 100GB | -| Large | $0.1517 | ~$110 | 2-core ARM (dedicated) | 8 GB | 160 | 300 | 200GB | -| XL | $0.2877 | ~$210 | 4-core ARM (dedicated) | 16 GB | 240 | 700 | 500GB | -| 2XL | $0.562 | ~$410 | 8-core ARM (dedicated) | 32 GB | 380 | 1500 | 1TB | -| 4XL | $1.32 | ~$960 | 16-core ARM (dedicated) | 64 GB | 480 | 3000 | 2TB | -| 8XL | $2.562 | ~$1,870 | 32-core ARM (dedicated) | 128 GB | 490 | 6000 | 4TB | -| 12XL | $3.836 | ~$2,800 | 48-core ARM (dedicated) | 192 GB | 500 | 9000 | 6TB | -| 16XL | $5.12 | ~$3,730 | 64-core ARM (dedicated) | 256 GB | 500 | 12,000 | 10TB | + + +Free plan resources subject to changes. + + + +| Plan | Hourly Price USD | Monthly Price USD | CPU | Memory | Connections: Direct | Connections: Pooler | Recommended Maximum DB Size | +| ----------- | ---------------- | ----------------- | ----------------------- | ------------ | ------------------- | ------------------- | --------------------------- | +| Nano (free) | $0 | $0 | Shared | Up to 0.5 GB | 60 | 200 | 500MB | +| Micro | $0.01344 | ~$10 | 2-core ARM (shared) | 1 GB | 60 | 200 | 10GB | +| Small | $0.0206 | ~$15 | 2-core ARM (shared) | 2 GB | 90 | 400 | 50GB | +| Medium | $0.0822 | ~$60 | 2-core ARM (shared) | 4 GB | 120 | 600 | 100GB | +| Large | $0.1517 | ~$110 | 2-core ARM (dedicated) | 8 GB | 160 | 800 | 200GB | +| XL | $0.2877 | ~$210 | 4-core ARM (dedicated) | 16 GB | 240 | 1,000 | 500GB | +| 2XL | $0.562 | ~$410 | 8-core ARM (dedicated) | 32 GB | 380 | 1,500 | 1TB | +| 4XL | $1.32 | ~$960 | 16-core ARM (dedicated) | 64 GB | 480 | 3,000 | 2TB | +| 8XL | $2.562 | ~$1,870 | 32-core ARM (dedicated) | 128 GB | 490 | 6,000 | 4TB | +| 12XL | $3.836 | ~$2,800 | 48-core ARM (dedicated) | 192 GB | 500 | 9,000 | 6TB | +| 16XL | $5.12 | ~$3,730 | 64-core ARM (dedicated) | 256 GB | 500 | 12,000 | 10TB | Number of connections above are recommended values. @@ -45,18 +52,19 @@ When considering compute upgrades, assess whether your bottlenecks are hardware- SSD Disks are attached to your servers and the disk performance depends on the compute add-on of your instance. Disk IO refers to two metrics: throughput (Megabits per Second) and IOPS (Input/Output Operations per Second). Disk throughput is capped at 1,048 Mbps and IOPS is capped at 3,000 IOPS for all compute add-ons. -| Plan | Baseline Disk Throughput | Baseline IOPS | -| ------ | ------------------------ | ------------- | -| Micro | 87 Mbps | 500 IOPS | -| Small | 174 Mbps | 1,000 IOPS | -| Medium | 347 Mbps | 2,000 IOPS | -| Large | 630 Mbps | 3,000 IOPS | -| XL | 1,048 Mbps | 3,000 IOPS | -| 2XL | 1,048 Mbps | 3,000 IOPS | -| 4XL | 1,048 Mbps | 3,000 IOPS | -| 8XL | 1,048 Mbps | 3,000 IOPS | -| 12XL | 1,048 Mbps | 3,000 IOPS | -| 16XL | 1,048 Mbps | 3,000 IOPS | +| Plan | Baseline Disk Throughput | Baseline IOPS | +| ----------- | ------------------------ | ------------- | +| Nano (free) | 43 Mbps | 250 IOPS | +| Micro | 87 Mbps | 500 IOPS | +| Small | 174 Mbps | 1,000 IOPS | +| Medium | 347 Mbps | 2,000 IOPS | +| Large | 630 Mbps | 3,000 IOPS | +| XL | 1,048 Mbps | 3,000 IOPS | +| 2XL | 1,048 Mbps | 3,000 IOPS | +| 4XL | 1,048 Mbps | 3,000 IOPS | +| 8XL | 1,048 Mbps | 3,000 IOPS | +| 12XL | 1,048 Mbps | 3,000 IOPS | +| 16XL | 1,048 Mbps | 3,000 IOPS | [Contact us](https://supabase.com/contact/enterprise) if you require a plan with higher disk throughput and IOPS. @@ -74,18 +82,19 @@ If you're unsure of how much throughput or IOPS your application requires, you c The maximum number of replication slots and WAL senders depends on your compute add-on plan, as follows: -| Plan | Max Replication Slots | Max WAL Senders | -| ------ | --------------------- | --------------- | -| Micro | 5 | 5 | -| Small | 5 | 5 | -| Medium | 5 | 5 | -| Large | 8 | 8 | -| XL | 24 | 24 | -| 2XL | 80 | 80 | -| 4XL | 80 | 80 | -| 8XL | 80 | 80 | -| 12XL | 80 | 80 | -| 16XL | 80 | 80 | +| Plan | Max Replication Slots | Max WAL Senders | +| ----------- | --------------------- | --------------- | +| Nano (free) | 5 | 5 | +| Micro | 5 | 5 | +| Small | 5 | 5 | +| Medium | 5 | 5 | +| Large | 8 | 8 | +| XL | 24 | 24 | +| 2XL | 80 | 80 | +| 4XL | 80 | 80 | +| 8XL | 80 | 80 | +| 12XL | 80 | 80 | +| 16XL | 80 | 80 | diff --git a/apps/docs/content/guides/platform/database-size.mdx b/apps/docs/content/guides/platform/database-size.mdx index b3ed9a3bd4d..55005add558 100644 --- a/apps/docs/content/guides/platform/database-size.mdx +++ b/apps/docs/content/guides/platform/database-size.mdx @@ -59,6 +59,12 @@ Projects on the Pro plan and above have auto-scaling Disk Storage. Disk Storage expands automatically when the database reaches 90% of the disk size. The disk is expanded to be 50% larger (e.g., 8GB -> 12GB). Auto-scaling can only take place once every 6 hours. If within those 6 hours you reach 95% of the disk space, your project will enter read-only mode. + + +The automatic resize operation will add an additional 50% capped to a maximum of 200GB. If 50% of your current usage is more than 200GB then only 200GB will be added to your disk (e.g. a size of 1500GB will resize to 1700GB). + + + The Disk Storage Size can also be manually expanded on the [Database settings page](https://supabase.com/dashboard/project/_/settings/database). The maximum default you can expand the Disk Storage to is 200GB. If you wish to manually expand it to any more than 200GB, please [contact us](https://supabase.com/dashboard/support/new) to discuss expanding the 200GB limit. diff --git a/apps/docs/content/guides/platform/org-based-billing.mdx b/apps/docs/content/guides/platform/org-based-billing.mdx index fd036a364a4..7a5f68f173a 100644 --- a/apps/docs/content/guides/platform/org-based-billing.mdx +++ b/apps/docs/content/guides/platform/org-based-billing.mdx @@ -92,7 +92,7 @@ Additionally, Compute Credits are given to you not only for the first month but ## Unified egress -Each organization receives a total egress quota (eg. 250GB on the Pro plan) which can be used for anything - Storage, Realtime, Auth, Functions or Database. +Each organization receives a total egress quota (eg. 250GB on the Pro plan) which can be used for anything - Storage, Realtime, Auth, Functions, Supavisor or Database. ### Included egress quota diff --git a/apps/docs/content/guides/platform/performance.mdx b/apps/docs/content/guides/platform/performance.mdx index ff9846a0f60..a08e5d5b619 100644 --- a/apps/docs/content/guides/platform/performance.mdx +++ b/apps/docs/content/guides/platform/performance.mdx @@ -175,21 +175,7 @@ You can pair the information available from `pg_stat_statements` with the detail ## Optimizing the number of connections -By default, the number of connections allowed to Postgres and Supavisor is configured based on the resources available to the database. - -| Compute Add-on | Postgresql connections | Supavisor connections | -| -------------- | ---------------------- | --------------------- | -| - (Free plan) | 30 | 200 | -| Micro | 60 | 200 | -| Small | 90 | 200 | -| Medium | 120 | 200 | -| Large | 160 | 300 | -| XL | 240 | 700 | -| 2XL | 380 | 1500 | -| 4XL | 480 | 3000 | -| 8XL | 490 | 6000 | -| 12XL | 500 | 9000 | -| 16XL | 500 | 12000 | +The default connection limits for Postgres and Supavisor is based on your compute size. See the default connection numbers in the [Compute Add-ons](/docs/guides/platform/compute-add-ons) section. If the number of connections is insufficient, you will receive the following error upon connecting to the DB: diff --git a/apps/docs/content/guides/platform/read-replicas.mdx b/apps/docs/content/guides/platform/read-replicas.mdx index 93f88e12ecb..82511dc83a3 100644 --- a/apps/docs/content/guides/platform/read-replicas.mdx +++ b/apps/docs/content/guides/platform/read-replicas.mdx @@ -51,10 +51,11 @@ A project needs to satisfy these requirements to deploy a Read Replica: - Support for projects on Fly.io is coming. 1. Running on at least a [Small compute add-on](/docs/guides/platform/compute-add-ons). - Read Replicas are currently placed on the same compute instance as the database to make sure they can keep up with the Primary's activities. -1. Using [physical backups](/docs/guides/platform/backups#point-in-time-recovery) - - Physical backups are automatically enabled if using [PITR](/docs/guides/platform/backups#point-in-time-recovery) 1. Running on Postgres 15. - For projects running on older versions of PostgreSQL, you will need to [upgrade to the latest platform version](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade). +1. Using [physical backups](/docs/guides/platform/backups#point-in-time-recovery) + - Physical backups are automatically enabled if using [PITR](/docs/guides/platform/backups#point-in-time-recovery) + - If you're not using PITR, you'll be able to switch to physical backups as part of the Read Replica setup process. Note that physical backups can't be downloaded from the dashboard in the way logical backups can. ## Getting started diff --git a/apps/docs/content/guides/platform/sso.mdx b/apps/docs/content/guides/platform/sso.mdx index dffb85fca2e..2e32c46b6a8 100644 --- a/apps/docs/content/guides/platform/sso.mdx +++ b/apps/docs/content/guides/platform/sso.mdx @@ -5,7 +5,7 @@ description: 'General information about enabling single sign-on (SSO) for your o -Looking for docs on how to add Single Sign-On support in your Supabase project? Head on over to [Single Sign-On with SAML 2.0 for Projects](/docs/guides/auth/sso/auth-sso-saml). +Looking for docs on how to add Single Sign-On support in your Supabase project? Head on over to [Single Sign-On with SAML 2.0 for Projects](/docs/guides/auth/enterprise-sso/auth-sso-saml). diff --git a/apps/docs/content/guides/resources/examples.mdx b/apps/docs/content/guides/resources/examples.mdx index 0e3e2c4ea45..177df12f0c3 100644 --- a/apps/docs/content/guides/resources/examples.mdx +++ b/apps/docs/content/guides/resources/examples.mdx @@ -150,6 +150,7 @@ Build a basic Todo List with Supabase and your favorite frontend framework: - Supabase + Ory Cloud [Github](https://github.com/ory/examples/tree/master/supabase-ory-cloud) - Supabase Auth with React Native + Next.js (Monorepo) [Github](https://github.com/mateoguzmana/react-native-next-supabase-auth-monorepo) - Supabase Auth with Nuxt3 [Github](https://github.com/zackha/supaAuth) +- Supabase Auth with Hono [Github](https://github.com/CarlosZiegler/hono-supabase) ### Blog posts diff --git a/apps/docs/content/guides/storage/uploads/resumable-uploads.mdx b/apps/docs/content/guides/storage/uploads/resumable-uploads.mdx index 73e07e7067b..75692c6594c 100644 --- a/apps/docs/content/guides/storage/uploads/resumable-uploads.mdx +++ b/apps/docs/content/guides/storage/uploads/resumable-uploads.mdx @@ -31,7 +31,7 @@ Supabase Storage implements the [TUS protocol](https://tus.io/) to enable resuma const projectId = '' async function uploadFile(bucketName, fileName, file) { - const { data: session } = await supabase.auth.session() + const { data: { session } } = await supabase.auth.getSession() return new Promise((resolve, reject) => { var upload = new tus.Upload(file, { diff --git a/apps/docs/data/footer.ts b/apps/docs/data/footer.ts index 9ea6bba69ae..d076d36159d 100644 --- a/apps/docs/data/footer.ts +++ b/apps/docs/data/footer.ts @@ -23,10 +23,13 @@ export const primaryLinks = [ ] export const secondaryLinks = [ - { title: 'Contributing', url: '/handbook/contributing' }, + { + title: 'Contributing', + url: 'https://github.com/supabase/supabase/blob/master/apps/docs/DEVELOPERS.md', + }, { title: 'Author Styleguide', - url: 'https://github.com/supabase/supabase/blob/master/DEVELOPERS.md', + url: 'https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md', }, { title: 'Open Source', url: 'https://supabase.com/open-source' }, { title: 'SupaSquad', url: 'https://supabase.com/supasquad' }, diff --git a/apps/docs/hooks/useHash.ts b/apps/docs/hooks/useHash.ts index 92c0cec4fb8..3c6f9567dab 100644 --- a/apps/docs/hooks/useHash.ts +++ b/apps/docs/hooks/useHash.ts @@ -14,7 +14,7 @@ const useHash = () => { return () => { window.removeEventListener('hashchange', hashChangeHandler) } - }, []) + }, [hashChangeHandler]) const updateHash = useCallback( (newHash) => { @@ -23,7 +23,7 @@ const useHash = () => { [hash] ) - return [hash, updateHash] + return [hash, updateHash] as const } export default useHash diff --git a/apps/docs/hooks/useManualRerender.ts b/apps/docs/hooks/useManualRerender.ts new file mode 100644 index 00000000000..4fde23deb2d --- /dev/null +++ b/apps/docs/hooks/useManualRerender.ts @@ -0,0 +1,17 @@ +import { useEffect, useReducer } from 'react' + +/** + * An escape hatch to manually trigger component rerenders in response to + * external events, such as fired custom events. + */ +const useRerenderOnEvt = (event: string, listeningElem?: Document | Window | HTMLElement) => { + const [, rerender] = useReducer((state) => !state, true) + + useEffect(() => { + const elem = listeningElem ?? window + elem.addEventListener(event, rerender) + return () => elem.removeEventListener(event, rerender) + }, [event, listeningElem, rerender]) +} + +export { useRerenderOnEvt } diff --git a/apps/docs/layouts/DefaultLayout.tsx b/apps/docs/layouts/DefaultLayout.tsx index 6bfc53a2564..f6b3f8bf230 100644 --- a/apps/docs/layouts/DefaultLayout.tsx +++ b/apps/docs/layouts/DefaultLayout.tsx @@ -1,91 +1,6 @@ -import { MDXProvider } from '@mdx-js/react' -import { NextSeo } from 'next-seo' -import Head from 'next/head' -import { useRouter } from 'next/router' -import { FC, PropsWithChildren } from 'react' -import components from '~/components' -import TableOfContents from '~/components/TableOfContents' -import { MainSkeleton } from './MainSkeleton' - -interface Props { - meta: { - title: string - description?: string - hide_table_of_contents?: boolean - video?: string - tocVideo?: string - canonical?: string - } - children: any - toc?: any - menuItems: any -} - -const Layout: FC = (props: Props) => { - const { asPath } = useRouter() - - const hasTableOfContents = - props.toc !== undefined && - props.toc.json.filter((item) => item.lvl !== 1 && item.lvl <= 3).length > 0 - - return ( - <> - - {asPath === '/' ? 'Supabase Docs' : `${props.meta?.title} | Supabase Docs`} - - - - - - - -
-
-

{props.meta.title}

- {props.children} -
-
- {hasTableOfContents && !props.meta?.hide_table_of_contents && ( - - )} -
- - ) -} +import { type FC, type PropsWithChildren } from 'react' export const LayoutMainContent: FC> = ({ className, children, }) =>
{children}
- -export default Layout diff --git a/apps/docs/layouts/HomeLayout.tsx b/apps/docs/layouts/HomeLayout.tsx index 9f5e7d46320..7f2ff3de39a 100644 --- a/apps/docs/layouts/HomeLayout.tsx +++ b/apps/docs/layouts/HomeLayout.tsx @@ -6,30 +6,22 @@ import { FC } from 'react' import components from '~/components' import HomePageCover from '~/components/HomePageCover' import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import TableOfContents from '~/components/TableOfContents' import { LayoutMainContent } from './DefaultLayout' import { MainSkeleton } from './MainSkeleton' interface Props { meta: { title: string - description?: string - hide_table_of_contents?: boolean - video?: string canonical?: string + description?: string + video?: string } children: any - toc?: any - menuItems: any } const HomeLayout: FC = (props: Props) => { const { asPath } = useRouter() - const hasTableOfContents = - props.toc !== undefined && - props.toc.json.filter((item) => item.lvl !== 1 && item.lvl <= 3).length > 0 - return ( <> @@ -72,16 +64,6 @@ const HomeLayout: FC = (props: Props) => { {props.children}
- {hasTableOfContents && !props.meta?.hide_table_of_contents && ( - - )} diff --git a/apps/docs/layouts/MainSkeleton.tsx b/apps/docs/layouts/MainSkeleton.tsx index 2599585576f..ed0fef5cc36 100644 --- a/apps/docs/layouts/MainSkeleton.tsx +++ b/apps/docs/layouts/MainSkeleton.tsx @@ -6,141 +6,142 @@ import { type CSSProperties, type PropsWithChildren, memo, useEffect } from 'rea import { cn } from 'ui' import Footer from '~/components/Navigation/Footer' +import HomeMenuIconPicker from '~/components/Navigation/NavigationMenu/HomeMenuIconPicker' import NavigationMenu, { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar' import { menuState, useMenuMobileOpen } from '~/hooks/useMenuState' const levelsData = { home: { - icon: '/docs/img/icons/menu/home', + icon: 'home', name: 'Home', }, gettingstarted: { - icon: '/docs/img/icons/menu/getting-started', + icon: 'getting-started', name: 'Getting Started', }, database: { - icon: '/docs/img/icons/menu/database', + icon: 'database', name: 'Database', }, api: { - icon: '/docs/img/icons/menu/rest', + icon: 'rest', name: 'REST API', }, graphql: { - icon: '/docs/img/icons/menu/graphql', + icon: 'graphql', name: 'GraphQL', }, auth: { - icon: '/docs/img/icons/menu/auth', + icon: 'auth', name: 'Auth', }, functions: { - icon: '/docs/img/icons/menu/functions', + icon: 'edge-functions', name: 'Edge Functions', }, realtime: { - icon: '/docs/img/icons/menu/realtime', + icon: 'realtime', name: 'Realtime', }, analytics: { - icon: '/docs/img/icons/menu/analytics', + icon: 'analytics', name: 'Analytics', }, storage: { - icon: '/docs/img/icons/menu/storage', + icon: 'storage', name: 'Storage', }, ai: { - icon: '/docs/img/icons/menu/ai', + icon: 'ai', name: 'AI & Vectors', }, supabase_cli: { - icon: '/docs/img/icons/menu/reference-cli', + icon: 'reference-cli', name: 'Supabase CLI', }, platform: { - icon: '/docs/img/icons/menu/platform', + icon: 'platform', name: 'Platform', }, resources: { - icon: '/docs/img/icons/menu/resources', + icon: 'resources', name: 'Resources', }, self_hosting: { - icon: '/docs/img/icons/menu/self-hosting', + icon: 'self-hosting', name: 'Self-Hosting', }, integrations: { - icon: '/docs/img/icons/menu/integrations', + icon: 'integrations', name: 'Integrations', }, reference_javascript_v1: { - icon: '/docs/img/icons/menu/reference-javascript', + icon: 'reference-javascript', name: 'Javascript Reference v1.0', }, reference_javascript_v2: { - icon: '/docs/img/icons/menu/reference-javascript', + icon: 'reference-javascript', name: 'Javascript Reference v2.0', }, reference_dart_v1: { - icon: '/docs/img/icons/menu/reference-dart', + icon: 'reference-dart', name: 'Dart Reference v1.0', }, reference_dart_v2: { - icon: '/docs/img/icons/menu/reference-dart', + icon: 'reference-dart', name: 'Dart Reference v2.0', }, reference_csharp_v0: { - icon: '/docs/img/icons/menu/reference-csharp', + icon: 'reference-csharp', name: 'C# Reference v0.0', }, reference_python_v2: { - icon: '/docs/img/icons/menu/reference-python', + icon: 'reference-python', name: 'Python Reference v2.0', }, reference_swift_v1: { - icon: '/docs/img/icons/menu/reference-swift', + icon: 'reference-swift', name: 'Swift Reference v1.0', }, reference_swift_v2: { - icon: '/docs/img/icons/menu/reference-swift', + icon: 'reference-swift', name: 'Swift Reference v2.0', }, reference_kotlin_v1: { - icon: '/docs/img/icons/menu/reference-kotlin', + icon: 'reference-kotlin', name: 'Kotlin Reference v1.0', }, reference_kotlin_v2: { - icon: '/docs/img/icons/menu/reference-kotlin', + icon: 'reference-kotlin', name: 'Kotlin Reference v2.0', }, reference_cli: { - icon: '/docs/img/icons/menu/reference-cli', + icon: 'reference-cli', name: 'CLI Reference', }, reference_api: { - icon: '/docs/img/icons/menu/reference-api', + icon: 'reference-api', name: 'Management API Reference', }, reference_self_hosting_auth: { - icon: '/docs/img/icons/menu/reference-auth', + icon: 'reference-auth', name: 'Auth Server Reference', }, reference_self_hosting_storage: { - icon: '/docs/img/icons/menu/reference-storage', + icon: 'reference-storage', name: 'Storage Server Reference', }, reference_self_hosting_realtime: { - icon: '/docs/img/icons/menu/reference-realtime', + icon: 'reference-realtime', name: 'Realtime Server Reference', }, reference_self_hosting_analytics: { - icon: '/docs/img/icons/menu/reference-analytics', + icon: 'reference-analytics', name: 'Analytics Server Reference', }, reference_self_hosting_functions: { - icon: '/docs/img/icons/menu/reference-functions', + icon: 'reference-functions', name: 'Functions Server Reference', }, } @@ -187,8 +188,8 @@ const MobileHeader = memo(function MobileHeader({ menuId }: { menuId: MenuId })
- = (props) => { - const pathname = usePathname() - const [hash] = useHash() - - const articleRef = useRef() - const [tocList, setTocList] = useState([]) - const { asPath } = useRouter() const router = useRouter() @@ -52,31 +42,6 @@ const Layout: FC = (props) => { const EDIT_BUTTON_EXCLUDE_LIST = ['/404'] - useEffect(() => { - if (hash && tocList.length > 0) { - highlightSelectedTocItem(hash as string) - } - }, [hash, JSON.stringify(tocList)]) - - useEffect(() => { - const articleEl = articleRef.current as HTMLElement - - if (!articleRef.current) return - const headings = Array.from(articleEl.querySelectorAll('h2, h3')) - const newHeadings = headings - .filter((heading) => heading.id) - .map((heading) => { - const text = heading.textContent.replace('#', '') - const link = heading.querySelector('a').getAttribute('href') - const level = heading.tagName === 'H2' ? 2 : 3 - return { text, link, level } - }) - setTocList(newHeadings) - }, [pathname]) // needed to recalculate the toc when path changes - - const hasTableOfContents = tocList.length > 0 - const tocVideoPreview = `http://img.youtube.com/vi/${props.meta?.tocVideo}/0.jpg` - // page type, ie, Auth, Database, Storage etc const ogPageType = asPath.split('/')[2] // open graph image url constructor @@ -141,10 +106,9 @@ const Layout: FC = (props) => {

{props.meta.breadcrumb}

)}
)} - {!props.hideToc && hasTableOfContents && !props.meta?.hide_table_of_contents && ( - + /> )} diff --git a/apps/docs/layouts/ref/RefSubLayout.tsx b/apps/docs/layouts/ref/RefSubLayout.tsx index 2259a96273a..a14c56139be 100644 --- a/apps/docs/layouts/ref/RefSubLayout.tsx +++ b/apps/docs/layouts/ref/RefSubLayout.tsx @@ -134,12 +134,20 @@ const StickyHeader: FC = ({ icon, ...props }) => { } const Details: FC> = (props) => { - return
{props.children}
+ /** + * `min-w` is necessary because these are used as grid children, which have + * default `min-w-auto` + */ + return
{props.children}
} const Examples: FC> = (props) => { + /** + * `min-w` is necessary because these are used as grid children, which have + * default `min-w-auto` + */ return ( -
+
{props.children}
) diff --git a/apps/docs/layouts/tutorials/TutorialLayout.tsx b/apps/docs/layouts/tutorials/TutorialLayout.tsx deleted file mode 100644 index 4c369aeba16..00000000000 --- a/apps/docs/layouts/tutorials/TutorialLayout.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { MDXProvider } from '@mdx-js/react' -import Head from 'next/head' -import { FC, useEffect, useState } from 'react' -import components from '~/components' -import SideBar from '~/components/Navigation/SideBar' -import TableOfContents from '~/components/TableOfContents' - -interface Props { - meta: { - title: string - description?: string - hide_table_of_contents?: boolean - video?: string - tocVideo?: string - } - children: any - toc?: any - menuItems: any - currentPage: string -} - -const Layout: FC = (props: Props) => { - const [active, setActive] = useState(false) - - useEffect(() => { - setTimeout(function () { - setActive(true) - }, 150) - }, []) - - // const contentString = renderToString(props.children) - - // const content = serialize(contentString || '') - - // console.log('contentString', contentString) - - // const _toc = toc('#hello world', { maxdepth: 1, firsth1: false }) - - const hasTableOfContents = - props.toc !== undefined && - props.toc.json.filter((item) => item.lvl !== 1 && item.lvl <= 3).length > 0 - - return ( - <> - - {props.meta?.title} | Supabase - - - - - - - - - -
-
-

Tutorials

-
-

{props.meta.title}

-
- - -
-
- {hasTableOfContents && !props.meta?.hide_table_of_contents && ( - - )} -
- - ) -} - -export default Layout diff --git a/apps/docs/lib/fetch/feedback.ts b/apps/docs/lib/fetch/feedback.ts index 2d622925619..6bbb4bbd0d0 100644 --- a/apps/docs/lib/fetch/feedback.ts +++ b/apps/docs/lib/fetch/feedback.ts @@ -4,17 +4,19 @@ import { type ResponseError } from '~/types/fetch' import { post } from './fetchWrappers' type SendFeedbackVariables = { + title: string message: string + isHelpful: boolean pathname?: string } -export async function sendFeedback({ message, pathname }: SendFeedbackVariables) { - const { data, error } = await post('/platform/feedback/send', { +export async function sendFeedback({ message, pathname, title, isHelpful }: SendFeedbackVariables) { + const { data, error } = await post('/platform/feedback/docs', { body: { - message, - category: 'Feedback', - tags: ['docs-feedback'], - pathname, + page: pathname, + isHelpful, + title, + feedback: message, }, }) if (error) throw Error(`Couldn't send feedback`, { cause: error }) diff --git a/apps/docs/package.json b/apps/docs/package.json index 92bf9016101..428e3dc80ba 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -22,15 +22,15 @@ "@code-hike/mdx": "^0.9.0", "@mdx-js/loader": "^2.1.5", "@mdx-js/react": "^2.3.0", - "@next/bundle-analyzer": "^13.5.6", - "@next/mdx": "^13.5.6", + "@next/bundle-analyzer": "^14.1.4", + "@next/mdx": "^14.1.4", "@octokit/auth-app": "^6.0.3", - "@octokit/core": "^5.0.2", + "@octokit/core": "^5.1.0", "@octokit/graphql": "^7.0.2", "@octokit/plugin-paginate-graphql": "^4.0.0", "@radix-ui/react-accordion": "^1.1.2", "@supabase/auth-helpers-react": "^0.4.2", - "@supabase/supabase-js": "^2.39.3", + "@supabase/supabase-js": "^2.41.1", "@tailwindcss/container-queries": "^0.1.1", "@tanstack/react-query": "^5.13.4", "common": "*", @@ -54,11 +54,11 @@ "mdx-mermaid": "2.0.0-rc3", "mermaid": "^10.0.2", "micromark-extension-mdxjs": "^1.0.0", - "next": "^13.4.8", + "next": "^14.1.4", "next-mdx-remote": "^4.4.1", "next-plugin-yaml": "^1.0.1", "next-seo": "^6.5.0", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "openai": "^4.20.1", "openapi-fetch": "^0.8.2", "react": "^18.2.0", diff --git a/apps/docs/pages/_app.tsx b/apps/docs/pages/_app.tsx index 043fdeb0f83..27caa65f6e1 100644 --- a/apps/docs/pages/_app.tsx +++ b/apps/docs/pages/_app.tsx @@ -11,7 +11,7 @@ import { AuthProvider, ThemeProvider, useTelemetryProps, useThemeSandbox } from import Head from 'next/head' import { useRouter } from 'next/router' import { useCallback, useEffect, useState, type PropsWithChildren } from 'react' -import { PortalToast, TabsProvider } from 'ui' +import { PortalToast, PromoToast, TabsProvider } from 'ui' import { CommandMenuProvider } from 'ui-patterns/Cmdk' import { useConsent } from 'ui-patterns/ConsentToast' @@ -229,6 +229,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
+
diff --git a/apps/docs/pages/guides/cli/config.tsx b/apps/docs/pages/guides/cli/config.tsx index 193f25fca66..da10ec303ad 100644 --- a/apps/docs/pages/guides/cli/config.tsx +++ b/apps/docs/pages/guides/cli/config.tsx @@ -1,12 +1,14 @@ -import specFile from '~/spec/cli_v1_config.yaml' assert { type: 'yml' } -import { Parameter } from '~/lib/refGenerator/refTypes' -import ReactMarkdown from 'react-markdown' -import GuidesTableOfContents from '~/components/GuidesTableOfContents' -import { Heading } from '~/components/CustomHTMLElements' import Head from 'next/head' -import { CodeBlock } from 'ui' -import { MainSkeleton } from '~/layouts/MainSkeleton' +import ReactMarkdown from 'react-markdown' + +import { CodeBlock, cn } from 'ui' + +import { Heading } from '~/components/CustomHTMLElements' +import GuidesTableOfContents from '~/components/GuidesTableOfContents' import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' +import { MainSkeleton } from '~/layouts/MainSkeleton' +import { Parameter } from '~/lib/refGenerator/refTypes' +import specFile from '~/spec/cli_v1_config.yaml' assert { type: 'yml' } // Parameters are grouped on the page by tag const tocList = [] @@ -41,14 +43,15 @@ export default function Config() {
{content}
-
-
- - On this page - - -
-
+ diff --git a/apps/docs/pages/guides/database/database-linter.tsx b/apps/docs/pages/guides/database/database-linter.tsx new file mode 100644 index 00000000000..948e91d8355 --- /dev/null +++ b/apps/docs/pages/guides/database/database-linter.tsx @@ -0,0 +1,190 @@ +import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' +import { Octokit } from '@octokit/core' +import { capitalize } from 'lodash' +import { GetStaticProps, InferGetStaticPropsType } from 'next' +import { MDXRemote } from 'next-mdx-remote' +import { serialize } from 'next-mdx-remote/serialize' +import remarkGfm from 'remark-gfm' +import rehypeSlug from 'rehype-slug' + +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } +import { Tabs } from 'ui' + +import components from '~/components' +import { Heading } from '~/components/CustomHTMLElements' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' +import Layout from '~/layouts/DefaultGuideLayout' +import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' +import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' +import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' +import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' + +// We fetch these docs at build time from an external repo +export const org = 'supabase' +export const repo = 'splinter' +export const branch = 'main' +export const docsDir = 'docs' + +const meta = { + title: 'Database Linter', + subtitle: 'Check your database for performance and security issues', +} + +const editLink = 'https://github.com/supabase/splinter/tree/main/docs' + +const markdownIntro = ` +You can use the Database Linter to check your database for issues such as missing indexes and improperly set-up RLS policies. + +## Using the linter + +In the dashboard, navigate to [Database Linter](/dashboard/project/_/database/linter) under Database. The linter runs automatically. You can also manually rerun it after you've resolved issues. +`.trim() + +const getBasename = (path: string) => path.split('/').at(-1).replace(/\.md$/, '') + +export default function ProjectLinterDocs({ + intro, + lints, +}: InferGetStaticPropsType) { + return ( + + + Available lints + + {lints.map((lint) => ( + +
+ +
+
+ ))} +
+
+ ) +} + +/** + * The GitHub repo uses relative links, which don't lead to the right locations + * in docs. + * + * @param url The original link, as written in the Markdown file + * @returns The rewritten link + */ +const urlTransform: (lints: Array<{ path: string }>) => UrlTransformFunction = (lints) => (url) => { + try { + const placeholderHostname = 'placeholder' + const { hostname, pathname, hash } = new URL(url, `http://${placeholderHostname}`) + + // Don't modify a url with a FQDN or a url that's only a hash + if (hostname !== placeholderHostname || pathname === '/') { + return url + } + + const relativePath = getBasename(pathname) + const section = lints.find(({ path }) => path === relativePath) + + if (section) { + const url = new URL(window.location.href) + url.searchParams.set('lint', relativePath) + return url.toString() + } + + // If we don't have this page in our docs, link to GitHub repo + return `https://github.com/${org}/${repo}/blob/${branch}${pathname}${hash}` + } catch (err) { + console.error('Error transforming markdown URL', err) + return url + } +} + +const transformMarkdown = async ( + rawContent: string, + { replacementLinks = [] }: { replacementLinks?: Array<{ path: string }> } = {} +) => { + const codeHikeOptions: CodeHikeConfig = { + theme: codeHikeTheme, + lineNumbers: true, + showCopyButton: true, + skipLanguages: [], + autoImport: false, + } + + const content = await serialize(rawContent, { + scope: { + chCodeConfig: codeHikeOptions, + }, + mdxOptions: { + remarkPlugins: [ + remarkGfm, + remarkMkDocsAdmonition, + remarkPyMdownTabs, + [removeTitle, meta.title], + [remarkCodeHike, codeHikeOptions], + ], + rehypePlugins: [[linkTransform, urlTransform(replacementLinks)], rehypeSlug], + }, + }) + + return content +} + +/** + * Fetch markdown from external repo and transform links + */ +export const getStaticProps = (async () => { + const octokit = new Octokit() + + const response = await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', { + owner: org, + repo: repo, + path: docsDir, + ref: branch, + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + }) + + if (response.status >= 400) { + throw Error(`Could not get contents of repo ${org}/${repo}`) + } + + if (!Array.isArray(response.data)) { + throw Error( + `Reading a directory, not a file. Should not reach this, solely to appease Typescript.` + ) + } + + const [intro, ...lints] = await Promise.all([ + await transformMarkdown(markdownIntro), + ...response.data + .filter(({ path }) => /docs\/\d+.+\.md$/.test(path)) + .map(async ({ path }, _, data) => { + const fileResponse = await fetch( + `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${path}` + ) + + if (fileResponse.status >= 400) { + throw Error(`Could not get contents of file ${org}/${repo}/${path}`) + } + + const rawContent = await fileResponse.text() + const content = await transformMarkdown(rawContent, { replacementLinks: data }) + + return { + path: getBasename(path), + content, + } + }), + ]) + + return { + props: { + intro, + lints, + }, + } +}) satisfies GetStaticProps diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx index 0d34ede0dcb..3879c045049 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx +++ b/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx @@ -35,11 +35,11 @@ const pageMap = [ remoteFile: 'airtable.md', }, { - slug: 's3', + slug: 'auth0', meta: { - title: 'AWS S3', + title: 'Auth0', }, - remoteFile: 's3.md', + remoteFile: 'auth0.md', }, { slug: 'bigquery', @@ -55,6 +55,13 @@ const pageMap = [ }, remoteFile: 'clickhouse.md', }, + { + slug: 'cognito', + meta: { + title: 'AWS Cognito', + }, + remoteFile: 'cognito.md', + }, { slug: 'firebase', meta: { @@ -69,6 +76,27 @@ const pageMap = [ }, remoteFile: 'logflare.md', }, + { + slug: 'mssql', + meta: { + title: 'MSSQL', + }, + remoteFile: 'mssql.md', + }, + { + slug: 'redis', + meta: { + title: 'Redis', + }, + remoteFile: 'redis.md', + }, + { + slug: 's3', + meta: { + title: 'AWS S3', + }, + remoteFile: 's3.md', + }, { slug: 'stripe', meta: { diff --git a/apps/docs/pages/reference/realtime/config.tsx b/apps/docs/pages/reference/realtime/config.tsx deleted file mode 100644 index 8a25754c342..00000000000 --- a/apps/docs/pages/reference/realtime/config.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import fs from 'fs' -import matter from 'gray-matter' -import components from '~/components/index' -import { MDXRemote } from 'next-mdx-remote' -import { serialize } from 'next-mdx-remote/serialize' - -import specFile from '~/spec/realtime_v0_config.yaml' assert { type: 'yml' } -import { Parameter } from '~/lib/refGenerator/refTypes' - -import ReactMarkdown from 'react-markdown' - -// Parameters are grouped on the page by tag -const TAGS = ['general', 'database'] - -export default function Config(props) { - return ( -
-
-
-

{specFile.info.title} Configuration

- {specFile.info.description} -
-
- {props.docs - .filter((doc) => doc.introPage) - .map((item) => ( - - ))} -
- {TAGS.map((tag) => - specFile.parameters - .filter((param: Parameter) => param.tags[0] === tag) - .map((parameter: Parameter, index) => ( -
- {index === 0 &&

{tag} Settings

} -
-
-

- $ - {parameter.title} -

-
-
-
-

- {parameter.description} -

-
-
- Required: {parameter.required.toString()} -
-
- Default: - - {parameter.default ? parameter.default.toString() : 'None'} - -
-
-
- {parameter.links && - parameter.links.map((link) => ( -
-

See also:

-
  • - {link.name} -
  • -
    - ))} -
    -
    -
    -
    -
    - )) - )} -
    -
    -
    -
    - ) -} -export async function getServerSideProps() { - // an array of ids of the intro sections for this library - const introPages = ['realtime'] - - const pages = [...introPages] - - // Grab custom markdown intro page files - const allMarkdownDocs = await Promise.all( - pages.map(async (x: any, i) => { - const pathName = `docs/ref/realtime/${x}.mdx` - - const markdownExists = fs.existsSync(pathName) - - const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : '' - const { data, content } = matter(fileContents) - - return { - id: x, - title: x, - // ...content, - meta: data, - introPage: introPages.includes(x), - content: content ? await serialize(content || '') : null, - } - }) - ) - - return { - props: { - docs: allMarkdownDocs, - }, - } -} diff --git a/apps/docs/pages/reference/storage/[...slug].tsx b/apps/docs/pages/reference/storage/[...slug].tsx deleted file mode 100644 index 6e30ee79aa5..00000000000 --- a/apps/docs/pages/reference/storage/[...slug].tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { CodeBlock, Tabs } from 'ui' -import specFile from '~/spec/transforms/storage_v0_openapi_deparsed.json' assert { type: 'json' } -import { gen_v3 } from '~/lib/refGenerator/helpers' - -import RefSubLayout from '~/layouts/ref/RefSubLayout' -import React from 'react' - -export type AcceptedValue = { - id: string - name: string - type: 'string' | 'boolean' | 'object' - description?: string -} - -export type Flag = { - id: string - name: string - description: string - default_value: string - accepted_values: AcceptedValue[] -} - -export type ApiParameter = { - example: string - in: string - name: string - required: boolean - schema: { - type: string - example: string - } -} - -// @ts-ignore -const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' }) - -export default function Config() { - return ( - -
    -
    -
    -

    {generatedSpec.info.title}

    -

    {generatedSpec.info.description}

    -
    - -
    - {generatedSpec.sections.map((section, i) => ( - -

    {section.title}

    - {section.operations.map((operation: any, index) => ( -
    - - -
    - - {operation.operation} - {operation.fullPath} - -
    - {/* Path Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'path') - .length > 0 && ( -
    -

    Path parameters

    -
      - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'path') - .map((parameter: any, indx: number) => ( -
    • -
      - {parameter.name} - - {parameter.required && ( -
      - REQUIRED -
      - )} -
      -
      -
      - Example: - - {parameter.example} - -
      -
    • - ))} -
    -
    - )} - - {/* Header Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'header') - .length > 0 && ( -
    -

    Header parameters

    -
      - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'header') - .map((parameter: any, i: number) => ( -
    • -
      - {parameter.name} - - {parameter.required && 'required'} - -
      -
      - Example: - - {parameter.example} - -
      -
    • - ))} -
    -
    - )} -
    - -

    Responses

    - - {operation.responseList.map((response: any, i: number) => ( - -

    {response.description}

    - {response?.content && response?.content['application/json'] && ( -
    - - {JSON.stringify(response.content['application/json'], null, 2)} - -
    - )} -
    - ))} -
    -
    -
    -
    - ))} -
    - ))} -
    -
    -
    -
    - ) -} diff --git a/apps/docs/pages/reference/storage/config.tsx b/apps/docs/pages/reference/storage/config.tsx deleted file mode 100644 index ba26fafe1dd..00000000000 --- a/apps/docs/pages/reference/storage/config.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import specFile from '~/spec/storage_v0_config.yaml' assert { type: 'yml' } -import { Parameter } from '~/lib/refGenerator/refTypes' - -import ReactMarkdown from 'react-markdown' - -// Parameters are grouped on the page by tag -const TAGS = ['general', 'multitenant'] -// console.log(specFile) -export default function Config() { - return ( -
    -
    -
    -

    {specFile.info.title} Configuration

    - {specFile.info.description} -
    - {TAGS.map((tag) => - specFile.parameters - .filter((param: Parameter) => param.tags[0] === tag) - .map((parameter: Parameter, index) => ( -
    - {index === 0 &&

    {tag} Settings

    } -
    -
    -

    - $ - {parameter.title} -

    -
    -
    -
    -

    - {parameter.description} -

    -
    -
    - Required: {parameter.required.toString()} -
    -
    - Default: - - {parameter.default ? parameter.default.toString() : 'None'} - -
    -
    -
    - {parameter.links && - parameter.links.map((link) => ( -
    -

    See also:

    -
  • - {link.name} -
  • -
    - ))} -
    -
    -
    -
    -
    - )) - )} -
    -
    -
    -
    - ) -} diff --git a/apps/docs/public/favicon/browserconfig.xml b/apps/docs/public/favicon/browserconfig.xml index c5541482230..1a8136def88 100644 --- a/apps/docs/public/favicon/browserconfig.xml +++ b/apps/docs/public/favicon/browserconfig.xml @@ -1,2 +1,2 @@ -#ffffff \ No newline at end of file +#ffffff \ No newline at end of file diff --git a/apps/docs/public/favicon/favicon-180x180.png b/apps/docs/public/favicon/favicon-180x180.png new file mode 100644 index 00000000000..3cf7f1132c8 Binary files /dev/null and b/apps/docs/public/favicon/favicon-180x180.png differ diff --git a/apps/docs/public/favicon/favicon-48x48.png b/apps/docs/public/favicon/favicon-48x48.png new file mode 100644 index 00000000000..40377a51b54 Binary files /dev/null and b/apps/docs/public/favicon/favicon-48x48.png differ diff --git a/apps/docs/public/favicon/manifest.json b/apps/docs/public/favicon/manifest.json index 3a90d23e45e..4efcf18e2ec 100644 --- a/apps/docs/public/favicon/manifest.json +++ b/apps/docs/public/favicon/manifest.json @@ -7,37 +7,37 @@ "background_color": "#1C1C1C", "icons": [ { - "src": "/android-icon-36x36.png", + "src": "/favicon/android-icon-36x36.png", "sizes": "36x36", "type": "image/png", "density": "0.75" }, { - "src": "/android-icon-48x48.png", + "src": "/favicon/android-icon-48x48.png", "sizes": "48x48", "type": "image/png", "density": "1.0" }, { - "src": "/android-icon-72x72.png", + "src": "/favicon/android-icon-72x72.png", "sizes": "72x72", "type": "image/png", "density": "1.5" }, { - "src": "/android-icon-96x96.png", + "src": "/favicon/android-icon-96x96.png", "sizes": "96x96", "type": "image/png", "density": "2.0" }, { - "src": "/android-icon-144x144.png", + "src": "/favicon/android-icon-144x144.png", "sizes": "144x144", "type": "image/png", "density": "3.0" }, { - "src": "/android-icon-192x192.png", + "src": "/favicon/android-icon-192x192.png", "sizes": "192x192", "type": "image/png", "density": "4.0" diff --git a/apps/docs/spec/supabase_js_v2.yml b/apps/docs/spec/supabase_js_v2.yml index d06268ef6fc..d9d829db21a 100644 --- a/apps/docs/spec/supabase_js_v2.yml +++ b/apps/docs/spec/supabase_js_v2.yml @@ -1346,7 +1346,7 @@ functions: notes: | - Sends an invite link to the user's email address. - The `inviteUserByEmail()` method is typically used by administrators to invite users to join the application. - - Note that PKCE is not supported when using `inviteUserByEmail`. This is because the browser initiating the invite is often different from the browser acecpting the invite which makes it difficult to provide the security guarantees required of the PKCE flow. + - Note that PKCE is not supported when using `inviteUserByEmail`. This is because the browser initiating the invite is often different from the browser accepting the invite which makes it difficult to provide the security guarantees required of the PKCE flow. examples: - id: invite-a-user name: Invite a user diff --git a/apps/docs/spec/supabase_kt_v2.yml b/apps/docs/spec/supabase_kt_v2.yml index 7215af5f062..a613cd2cbd6 100644 --- a/apps/docs/spec/supabase_kt_v2.yml +++ b/apps/docs/spec/supabase_kt_v2.yml @@ -2903,6 +2903,37 @@ functions: password = "example-password" } ``` + - id: sign-in-anonymously + title: 'signInAnonymously()' + notes: | + - Creates an anonymous user. + - The user can be retrieved by calling `supabase.auth.currentUserOrNull()`. + - It is recommended to set up captcha for anonymous sign-ins to prevent abuse. You can pass in the captcha token in the `options` param. + params: + - name: captchaToken + isOptional: true + type: String? + description: The captcha token when having captcha enabled. + - name: data + isOptional: true + type: JsonObject? or T + description: Extra user data to pass in. + examples: + - id: sign-in-anonymously + name: Create an anonymous user + isSpotlight: true + code: | + ```kotlin + supabase.auth.signInAnonymously(captchaToken = "token") + ``` + - id: sign-in-anonymously-with-user-metadata + name: Create an anonymous user with custom user metadata + isSpotlight: false + code: | + ```kotlin + supabase.auth.signInAnonymously(data = customUserData) + ``` + - id: sign-in-with-password title: 'signInWith()' $ref: '@supabase/gotrue-js.GoTrueClient.signInWithPassword' diff --git a/apps/docs/spec/supabase_py_v2.yml b/apps/docs/spec/supabase_py_v2.yml index 98185f7bf48..8d2620e7441 100644 --- a/apps/docs/spec/supabase_py_v2.yml +++ b/apps/docs/spec/supabase_py_v2.yml @@ -40,7 +40,8 @@ functions: code: | ``` import os - from supabase import create_client, Client, ClientOptions + from supabase import create_client, Client + from supabase.client import ClientOptions url: str = os.environ.get("SUPABASE_URL") key: str = os.environ.get("SUPABASE_KEY") diff --git a/apps/docs/spec/supabase_swift_v2.yml b/apps/docs/spec/supabase_swift_v2.yml index 0cd5c5df4c0..5cfd133983b 100644 --- a/apps/docs/spec/supabase_swift_v2.yml +++ b/apps/docs/spec/supabase_swift_v2.yml @@ -129,6 +129,29 @@ functions: redirectTo: URL(string: "https://example.com/welcome")! ) ``` + - id: sign-in-anonymously + title: "signInAnonymously()" + notes: | + - Returns an anonymous user + - It is recommended to set up captcha for anonymous sign-ins to prevent abuse. You can pass in the captcha token in the `options` param. + examples: + - id: sign-in-anonymously + name: Create an anonymous user + isSpotlight: true + code: | + ```swift + let session = try await supabase.auth.signInAnonymously(captchaToken: captchaToken) + ``` + - id: sign-in-anonymously-with-user-metadata + name: Create an anonymous user with custom user metadata + isSpotlight: false + code: | + ```swift + let session = try await supabase.auth.signInAnonymously( + data: customData, + captchaToken: captchaToken + ) + ``` - id: sign-in-with-password title: "signInWithPassword()" notes: | @@ -376,7 +399,7 @@ functions: ) ``` - id: get-user-identities - title: 'userIdentities()' + title: "userIdentities()" notes: | - The user needs to be signed in to call `userIdentities()`. examples: @@ -388,7 +411,7 @@ functions: let identities = try await supabase.auth.userIdentities() ``` - id: send-password-reauthentication - title: 'reauthenticate()' + title: "reauthenticate()" notes: | - This method is used together with `update(user:)` when a user's password needs to be updated. - If you require your user to reauthenticate before updating their password, you need to enable the **Secure password change** option in your [project's email provider settings](/dashboard/project/_/auth/providers). diff --git a/apps/docs/types/api.d.ts b/apps/docs/types/api.d.ts index 2cc2f1a9c47..c630c9ee527 100644 --- a/apps/docs/types/api.d.ts +++ b/apps/docs/types/api.d.ts @@ -41,6 +41,14 @@ export interface paths { /** Send exit survey to HubSpot */ post: operations['SendExitSurveyController_sendExitSurvey'] } + '/platform/feedback/upgrade': { + /** Send upgrade survey to survey_responses table */ + post: operations['SendUpgradeSurveyController_sendUpgradeSurvey'] + } + '/platform/feedback/docs': { + /** Send feedback on docs */ + post: operations['SendDocsFeedbackController_sendDocsFeedback'] + } '/platform/signup': { /** Sign up with email and password */ post: operations['SignUpController_signUp'] @@ -100,6 +108,10 @@ export interface paths { /** Gets project backups */ get: operations['BackupsController_getBackups'] } + '/platform/database/{ref}/backups/enable-physical-backups': { + /** Enable usage of physical backups */ + post: operations['BackupsController_enablePhysicalBackup'] + } '/platform/database/{ref}/backups/download': { /** Download project backup */ post: operations['BackupsController_downloadBackup'] @@ -822,14 +834,6 @@ export interface paths { /** Get GitHub connection branch */ get: operations['GitHubBranchesController_getConnectionBranch'] } - '/platform/integrations/github/pull-requests/{connectionId}': { - /** List GitHub connection pull requests */ - get: operations['GitHubPullRequestsController_getConnectionPullRequests'] - } - '/platform/integrations/github/pull-requests/{connectionId}/{branchName}': { - /** List GitHub pull requests for a specific branch */ - get: operations['GitHubPullRequestsController_validateConnectionBranch'] - } '/platform/integrations/github/repositories': { /** Gets GitHub repositories for user */ get: operations['GitHubRepositoriesController_listRepositories'] @@ -1020,6 +1024,10 @@ export interface paths { /** Gets project backups */ get: operations['BackupsController_getBackups'] } + '/v0/database/{ref}/backups/enable-physical-backups': { + /** Enable usage of physical backups */ + post: operations['BackupsController_enablePhysicalBackup'] + } '/v0/database/{ref}/backups/download': { /** Download project backup */ post: operations['BackupsController_downloadBackup'] @@ -1468,6 +1476,13 @@ export interface paths { */ patch: operations['BranchController_updateBranch'] } + '/v1/branches/{branch_id}/reset': { + /** + * Resets a database branch + * @description Resets the specified database branch + */ + post: operations['BranchController_resetBranch'] + } '/v1/projects': { /** * List all projects @@ -1640,6 +1655,18 @@ export interface paths { /** Updates a project's auth config */ patch: operations['V1AuthConfigController_updateV1AuthConfig'] } + '/v1/projects/{ref}/config/auth/third-party-auth': { + /** Lists all third-party auth integrations */ + get: operations['ThirdPartyAuthController_listTPAForProject'] + /** Creates a new third-party auth integration */ + post: operations['ThirdPartyAuthController_createTPAForProject'] + } + '/v1/projects/{ref}/config/auth/third-party-auth/{tpa_id}': { + /** Get a third-party integration */ + get: operations['ThirdPartyAuthController_getTPAForProject'] + /** Removes a third-party auth integration */ + delete: operations['ThirdPartyAuthController_deleteTPAForProject'] + } '/v1/projects/{ref}/config/auth/sso/providers': { /** Lists all SSO providers */ get: operations['ProvidersController_listAllProviders'] @@ -1860,6 +1887,19 @@ export interface components { additionalFeedback?: string exitAction?: string } + SendUpgradeSurveyBody: { + orgSlug?: string + prevPlan?: string + currentPlan?: string + reasons: string[] + additionalFeedback?: string + } + SendDocsFeedbackBody: { + page: string + isHelpful: boolean + title: string + feedback: string + } SignUpBody: { email: string password: string @@ -1899,11 +1939,13 @@ export interface components { MAILER_SUBJECTS_RECOVERY: string MAILER_SUBJECTS_EMAIL_CHANGE: string MAILER_SUBJECTS_MAGIC_LINK: string + MAILER_SUBJECTS_REAUTHENTICATION: string MAILER_TEMPLATES_INVITE_CONTENT: string MAILER_TEMPLATES_CONFIRMATION_CONTENT: string MAILER_TEMPLATES_RECOVERY_CONTENT: string MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT: string MAILER_TEMPLATES_MAGIC_LINK_CONTENT: string + MAILER_TEMPLATES_REAUTHENTICATION_CONTENT: string MFA_MAX_ENROLLED_FACTORS: number URI_ALLOW_LIST: string EXTERNAL_ANONYMOUS_USERS_ENABLED: boolean @@ -1959,6 +2001,8 @@ export interface components { HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI: string HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: boolean HOOK_CUSTOM_ACCESS_TOKEN_URI: string + HOOK_SEND_SMS_ENABLED: boolean + HOOK_SEND_SMS_URI: string EXTERNAL_APPLE_ENABLED: boolean EXTERNAL_APPLE_CLIENT_ID: string EXTERNAL_APPLE_SECRET: string @@ -2042,7 +2086,9 @@ export interface components { MAILER_SUBJECTS_RECOVERY?: string MAILER_SUBJECTS_EMAIL_CHANGE?: string MAILER_SUBJECTS_MAGIC_LINK?: string + MAILER_SUBJECTS_REAUTHENTICATION?: string MAILER_TEMPLATES_INVITE_CONTENT?: string + MAILER_TEMPLATES_REAUTHENTICATION_CONTENT?: string MAILER_TEMPLATES_CONFIRMATION_CONTENT?: string MAILER_TEMPLATES_RECOVERY_CONTENT?: string MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT?: string @@ -2107,6 +2153,8 @@ export interface components { HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI?: string HOOK_CUSTOM_ACCESS_TOKEN_ENABLED?: boolean HOOK_CUSTOM_ACCESS_TOKEN_URI?: string + HOOK_SEND_SMS_ENABLED?: boolean + HOOK_SEND_SMS_URI?: string EXTERNAL_APPLE_ENABLED?: boolean EXTERNAL_APPLE_CLIENT_ID?: string EXTERNAL_APPLE_SECRET?: string @@ -2207,6 +2255,7 @@ export interface components { updated_at?: string is_sso_user?: boolean deleted_at?: string + is_anonymous?: boolean } UsersResponse: { total: number @@ -2263,14 +2312,17 @@ export interface components { migrated_at: string | null } OrganizationResponse: { + /** @enum {string|null} */ + restriction_status: 'grace_period' | 'grace_period_over' | 'restricted' | null id: number slug: string name: string - billing_email: string + billing_email: string | null is_owner: boolean - stripe_customer_id: string - subscription_id?: string + stripe_customer_id: string | null + subscription_id: string | null opt_in_tags: string[] + restriction_data: Record } GetOrganizationByFlyOrganizationIdResponse: { slug: string @@ -2788,7 +2840,7 @@ export interface components { payment_method_card_details?: components['schemas']['PaymentMethodCardDetails'] billing_via_partner: boolean /** @enum {string} */ - billing_partner: 'fly' + billing_partner: 'fly' | 'aws' scheduled_plan_change: components['schemas']['ScheduledPlanChange'] | null customer_balance: number nano_enabled: boolean @@ -4565,6 +4617,7 @@ export interface components { branch_name?: string git_branch?: string reset_on_push?: boolean + persistent?: boolean } BranchResponse: { id: string @@ -4575,11 +4628,18 @@ export interface components { git_branch?: string pr_number?: number reset_on_push: boolean + persistent: boolean /** @enum {string} */ status: 'CREATING_PROJECT' | 'RUNNING_MIGRATIONS' | 'MIGRATIONS_PASSED' | 'MIGRATIONS_FAILED' created_at: string updated_at: string } + BranchDeleteResponse: { + message: string + } + BranchResetResponse: { + message: string + } V1DatabaseResponse: { /** @description Database host */ host: string @@ -4604,6 +4664,19 @@ export interface components { */ created_at: string database?: components['schemas']['V1DatabaseResponse'] + /** @enum {string} */ + status: + | 'ACTIVE_HEALTHY' + | 'ACTIVE_UNHEALTHY' + | 'COMING_UP' + | 'GOING_DOWN' + | 'INACTIVE' + | 'INIT_FAILED' + | 'REMOVED' + | 'RESTORING' + | 'UNKNOWN' + | 'UPGRADING' + | 'PAUSING' } V1CreateProjectBody: { /** @description Database password */ @@ -4925,11 +4998,13 @@ export interface components { mailer_subjects_invite: string | null mailer_subjects_magic_link: string | null mailer_subjects_recovery: string | null + mailer_subjects_reauthentication: string | null mailer_templates_confirmation_content: string | null mailer_templates_email_change_content: string | null mailer_templates_invite_content: string | null mailer_templates_magic_link_content: string | null mailer_templates_recovery_content: string | null + mailer_templates_reauthentication_content: string | null mfa_max_enrolled_factors: number | null password_hibp_enabled: boolean | null password_min_length: number | null @@ -5001,11 +5076,13 @@ export interface components { mailer_subjects_recovery?: string mailer_subjects_email_change?: string mailer_subjects_magic_link?: string + mailer_subjects_reauthentication?: string mailer_templates_invite_content?: string mailer_templates_confirmation_content?: string mailer_templates_recovery_content?: string mailer_templates_email_change_content?: string mailer_templates_magic_link_content?: string + mailer_templates_reauthentication_content?: string mfa_max_enrolled_factors?: number uri_allow_list?: string external_anonymous_users_enabled?: boolean @@ -5066,6 +5143,8 @@ export interface components { hook_password_verification_attempt_uri?: string hook_custom_access_token_enabled?: boolean hook_custom_access_token_uri?: string + hook_custom_sms_provider_enabled?: boolean + hook_custom_sms_provider_uri?: string external_apple_enabled?: boolean external_apple_client_id?: string external_apple_secret?: string @@ -5131,6 +5210,22 @@ export interface components { external_zoom_client_id?: string external_zoom_secret?: string } + CreateThirdPartyAuthBody: { + oidc_issuer_url?: string + jwks_url?: string + custom_jwks?: Record + } + ThirdPartyAuth: { + id: string + type: string + oidc_issuer_url?: string | null + jwks_url?: string | null + custom_jwks?: unknown + resolved_jwks?: unknown + inserted_at: string + updated_at: string + resolved_at?: string | null + } AttributeValue: { default?: Record | number | string | boolean name?: string @@ -5650,6 +5745,44 @@ export interface operations { } } } + /** Send upgrade survey to survey_responses table */ + SendUpgradeSurveyController_sendUpgradeSurvey: { + requestBody: { + content: { + 'application/json': components['schemas']['SendUpgradeSurveyBody'] + } + } + responses: { + 201: { + content: { + 'application/json': components['schemas']['SendFeedbackResponse'] + } + } + /** @description Failed to send upgrade survey */ + 500: { + content: never + } + } + } + /** Send feedback on docs */ + SendDocsFeedbackController_sendDocsFeedback: { + requestBody: { + content: { + 'application/json': components['schemas']['SendDocsFeedbackBody'] + } + } + responses: { + 201: { + content: { + 'application/json': components['schemas']['SendFeedbackResponse'] + } + } + /** @description Failed to send feedback for docs */ + 500: { + content: never + } + } + } /** Sign up with email and password */ SignUpController_signUp: { requestBody: { @@ -5870,7 +6003,13 @@ export interface operations { parameters: { path: { ref: string - template: 'confirmation' | 'email-change' | 'invite' | 'magic-link' | 'recovery' + template: + | 'confirmation' + | 'email-change' + | 'invite' + | 'magic-link' + | 'recovery' + | 'reauthentication' } } responses: { @@ -5986,6 +6125,24 @@ export interface operations { } } } + /** Enable usage of physical backups */ + BackupsController_enablePhysicalBackup: { + parameters: { + path: { + /** @description Project ref */ + ref: string + } + } + responses: { + 201: { + content: never + } + /** @description Failed to enable usage of physical backups */ + 500: { + content: never + } + } + } /** Download project backup */ BackupsController_downloadBackup: { parameters: { @@ -11079,52 +11236,6 @@ export interface operations { } } } - /** List GitHub connection pull requests */ - GitHubPullRequestsController_getConnectionPullRequests: { - parameters: { - query: { - pr_number: number[] - } - path: { - connectionId: number - } - } - responses: { - 200: { - content: { - 'application/json': Record[] - } - } - /** @description Failed to list GitHub connection pull requests */ - 500: { - content: never - } - } - } - /** List GitHub pull requests for a specific branch */ - GitHubPullRequestsController_validateConnectionBranch: { - parameters: { - query?: { - per_page?: number - page?: number - } - path: { - connectionId: number - branchName: string - } - } - responses: { - 200: { - content: { - 'application/json': Record[] - } - } - /** @description Failed to validate GitHub connection branch */ - 500: { - content: never - } - } - } /** Gets GitHub repositories for user */ GitHubRepositoriesController_listRepositories: { responses: { @@ -11176,7 +11287,13 @@ export interface operations { parameters: { path: { ref: string - template: 'confirmation' | 'email-change' | 'invite' | 'magic-link' | 'recovery' + template: + | 'confirmation' + | 'email-change' + | 'invite' + | 'magic-link' + | 'recovery' + | 'reauthentication' } } responses: { @@ -11845,7 +11962,9 @@ export interface operations { } responses: { 200: { - content: never + content: { + 'application/json': components['schemas']['BranchDeleteResponse'] + } } /** @description Failed to delete database branch */ 500: { @@ -11881,6 +12000,29 @@ export interface operations { } } } + /** + * Resets a database branch + * @description Resets the specified database branch + */ + BranchController_resetBranch: { + parameters: { + path: { + /** @description Branch ID */ + branch_id: string + } + } + responses: { + 201: { + content: { + 'application/json': components['schemas']['BranchResetResponse'] + } + } + /** @description Failed to reset database branch */ + 500: { + content: never + } + } + } /** * List all projects * @description Returns a list of all projects you've previously created. @@ -12833,6 +12975,89 @@ export interface operations { } } } + /** Lists all third-party auth integrations */ + ThirdPartyAuthController_listTPAForProject: { + parameters: { + path: { + /** @description Project ref */ + ref: string + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['ThirdPartyAuth'][] + } + } + 403: { + content: never + } + } + } + /** Creates a new third-party auth integration */ + ThirdPartyAuthController_createTPAForProject: { + parameters: { + path: { + /** @description Project ref */ + ref: string + } + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateThirdPartyAuthBody'] + } + } + responses: { + 201: { + content: { + 'application/json': components['schemas']['ThirdPartyAuth'] + } + } + 403: { + content: never + } + } + } + /** Get a third-party integration */ + ThirdPartyAuthController_getTPAForProject: { + parameters: { + path: { + /** @description Project ref */ + ref: string + tpa_id: string + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['ThirdPartyAuth'] + } + } + 403: { + content: never + } + } + } + /** Removes a third-party auth integration */ + ThirdPartyAuthController_deleteTPAForProject: { + parameters: { + path: { + /** @description Project ref */ + ref: string + tpa_id: string + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['ThirdPartyAuth'] + } + } + 403: { + content: never + } + } + } /** Lists all SSO providers */ ProvidersController_listAllProviders: { parameters: { diff --git a/apps/studio/Dockerfile b/apps/studio/Dockerfile index 2bf8e6e9b96..89eb1e38891 100644 --- a/apps/studio/Dockerfile +++ b/apps/studio/Dockerfile @@ -27,7 +27,7 @@ WORKDIR /app FROM base as turbo COPY . . -RUN npx turbo@1.30.0 prune --scope=studio --docker +RUN npx turbo@1.13.2 prune --scope=studio --docker # Install dev dependencies (only if needed) FROM base as deps diff --git a/apps/studio/components/grid/components/footer/Footer.tsx b/apps/studio/components/grid/components/footer/Footer.tsx index a2b7435596e..98d023d30c1 100644 --- a/apps/studio/components/grid/components/footer/Footer.tsx +++ b/apps/studio/components/grid/components/footer/Footer.tsx @@ -38,7 +38,7 @@ const Footer = ({ isLoading, isRefetching }: FooterProps) => { width={75} options={['definition', 'data']} activeOption={selectedView} - borderOverride="border-gray-500" + borderOverride="border" onClickOption={setSelectedView} /> diff --git a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx index bc866bad1b0..5df372be147 100644 --- a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx +++ b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx @@ -190,34 +190,30 @@ const Pagination = ({ isLoading: isLoadingRows = false }: PaginationProps) => { setIsConfirmPreviousModalOpen(false)} - onSelectConfirm={() => { + title="Confirm moving to previous page" + confirmLabel="Confirm" + onCancel={() => setIsConfirmPreviousModalOpen(false)} + onConfirm={() => { onConfirmPreviousPage() }} > - -

    - The currently selected lines will be deselected, do you want to proceed? -

    -
    +

    + The currently selected lines will be deselected, do you want to proceed? +

    setIsConfirmNextModalOpen(false)} - onSelectConfirm={() => { + title="Confirm moving to next page" + confirmLabel="Confirm" + onCancel={() => setIsConfirmNextModalOpen(false)} + onConfirm={() => { onConfirmNextPage() }} > - -

    - The currently selected lines will be deselected, do you want to proceed? -

    -
    +

    + The currently selected lines will be deselected, do you want to proceed? +

    )} diff --git a/apps/studio/components/grid/components/header/Header.tsx b/apps/studio/components/grid/components/header/Header.tsx index 03495120e1a..05c34564a71 100644 --- a/apps/studio/components/grid/components/header/Header.tsx +++ b/apps/studio/components/grid/components/header/Header.tsx @@ -377,7 +377,7 @@ const RowHeader = ({ table, sorts, filters }: RowHeaderProps) => { )} -
    +
    setIsOpen(false)} - onSelectConfirm={() => { + variant={'destructive'} + title="Confirm to delete" + confirmLabel="Delete" + confirmLabelLoading="Deleting" + onCancel={() => setIsOpen(false)} + onConfirm={() => { if (token) onDeleteToken(token.id) }} > - -

    - {`This action cannot be undone. Are you sure you want to delete "${token?.name}" token?`} -

    -
    +

    + {`This action cannot be undone. Are you sure you want to delete "${token?.name}" token?`} +

    ) diff --git a/apps/studio/components/interfaces/Account/AuditLogs.tsx b/apps/studio/components/interfaces/Account/AuditLogs.tsx index 2273b229437..5af85ed5787 100644 --- a/apps/studio/components/interfaces/Account/AuditLogs.tsx +++ b/apps/studio/components/interfaces/Account/AuditLogs.tsx @@ -3,10 +3,11 @@ import dayjs from 'dayjs' import { useEffect, useState } from 'react' import { Alert, Button, IconArrowDown, IconArrowUp, IconRefreshCw } from 'ui' -import { FilterPopover, LogDetailsPanel } from 'components/interfaces/AuditLogs' +import { LogDetailsPanel } from 'components/interfaces/AuditLogs' import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' import { DatePicker } from 'components/ui/DatePicker' +import { FilterPopover } from 'components/ui/FilterPopover' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import type { AuditLog } from 'data/organizations/organization-audit-logs-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx index 62d943f4895..c425c0276c2 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx @@ -64,29 +64,27 @@ const FirstStep = ({ visible, name, enroll, setName, isEnrolling, onClose }: Fir { + onCancel={onClose} + onConfirm={() => { enroll({ factorType: 'totp', friendlyName: name, }) }} > - -
    - setName(e.target.value)} - /> -
    -
    +
    + setName(e.target.value)} + /> +
    ) } @@ -152,65 +150,63 @@ const SecondStep = ({ { + onCancel={() => { // If a factor has been created (but not verified), unenroll it. This will be run as a // side effect so that it's not confusing to the user why the modal stays open while // unenrolling. if (factor) unenroll({ factorId: factor.id }) }} - onSelectConfirm={() => factor && challengeAndVerify({ factorId: factor.id, code })} + onConfirm={() => factor && challengeAndVerify({ factorId: factor.id, code })} > - - <> -
    - - Use an authenticator app to scan the following QR code, and provide the code from the - app to complete the enrolment. - + <> +
    + + Use an authenticator app to scan the following QR code, and provide the code from the + app to complete the enrolment. + +
    + {isLoading && ( +
    +
    - {isLoading && ( -
    - + )} + {factor && ( + <> +
    +
    + {factor.totp.uri} +
    - )} - {factor && ( - <> -
    -
    - {factor.totp.uri} -
    -
    -
    - - } - /> -
    -
    - setCode(e.target.value)} - /> -
    - - )} - - +
    + + } + /> +
    +
    + setCode(e.target.value)} + /> +
    + + )} + ) } diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx index 37fb4319ee9..9aed5f1f80b 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx @@ -34,45 +34,36 @@ const DeleteFactorModal = ({ factorId && unenroll({ factorId })} + onCancel={onClose} + onConfirm={() => factorId && unenroll({ factorId })} + alert={{ + title: lastFactorToBeDeleted + ? 'Multi-factor authentication will be disabled' + : 'This action cannot be undone', + description: lastFactorToBeDeleted + ? 'There are no other factors that are set up once you delete this factor, as such your account will no longer be guarded by multi-factor authentication' + : 'You will no longer be able to use this authenticator app for multi-factor authentication when signing in to the dashboard', + }} > - - - - - {lastFactorToBeDeleted - ? 'Multi-factor authentication will be disabled' - : 'This action cannot be undone'} - - - {lastFactorToBeDeleted - ? 'There are no other factors that are set up once you delete this factor, as such your account will no longer be guarded by multi-factor authentication' - : 'You will no longer be able to use this authenticator app for multi-factor authentication when signing in to the dashboard'} - - -
    -

    Before deleting this factor, consider:

    -
      - {lastFactorToBeDeleted ? ( - <> -
    • Adding another authenticator app as a factor prior to deleting
    • -
    • Ensure that your account does not need multi-factor authentication
    • - - ) : ( - <> -
    • Your backup authenticator app is still available to use
    • -
    • Adding another authenticator app thereafter as a backup
    • - - )} -
    -
    -
    +

    Before deleting this factor, consider:

    +
      + {lastFactorToBeDeleted ? ( + <> +
    • Adding another authenticator app as a factor prior to deleting
    • +
    • Ensure that your account does not need multi-factor authentication
    • + + ) : ( + <> +
    • Your backup authenticator app is still available to use
    • +
    • Adding another authenticator app thereafter as a backup
    • + + )} +
    ) } diff --git a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx index 8c4aa827cd7..1d922af9845 100644 --- a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx +++ b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx @@ -1,9 +1,10 @@ import { useMonaco } from '@monaco-editor/react' import { useTheme } from 'next-themes' -import { PropsWithChildren, useEffect } from 'react' +import { PropsWithChildren, useMemo } from 'react' import IncidentBanner from 'components/layouts/AppLayout/IncidentBanner' import { NoticeBanner } from 'components/layouts/AppLayout/NoticeBanner' +import { RestrictrionBanner } from 'components/layouts/AppLayout/RestrictionBanner' import { getTheme } from 'components/ui/CodeEditor' import { useFlag } from 'hooks' @@ -14,7 +15,9 @@ const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => { const ongoingIncident = useFlag('ongoingIncident') const showNoticeBanner = useFlag('showNoticeBanner') - useEffect(() => { + // Define the supabase theme for Monaco before anything is rendered. Using useEffect would sometime load the theme + // after the editor was loaded, so it looked off. useMemo will always be run before rendering + useMemo(() => { if (monaco && resolvedTheme) { const mode: any = getTheme(resolvedTheme) monaco.editor.defineTheme('supabase', mode) @@ -26,6 +29,7 @@ const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => {
    {ongoingIncident && } {showNoticeBanner && } +
    {children}
    diff --git a/apps/studio/components/interfaces/AuditLogs/index.ts b/apps/studio/components/interfaces/AuditLogs/index.ts index 082c6e83fde..25dafb4f074 100644 --- a/apps/studio/components/interfaces/AuditLogs/index.ts +++ b/apps/studio/components/interfaces/AuditLogs/index.ts @@ -1,2 +1 @@ -export { default as FilterPopover } from './FilterPopover' export { default as LogDetailsPanel } from './LogDetailsPanel' diff --git a/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx b/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx index bd35698a3f4..d6e8f48ae09 100644 --- a/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx +++ b/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx @@ -24,6 +24,7 @@ const CONFIRMATION: FormSchema = { - \`{{ .SiteURL }}\` : The URL of the site - \`{{ .Email }}\` : The user's email address - \`{{ .Data }}\` : The user's \`user_metadata\` +- \`{{ .RedirectTo }}\` : The URL of \`emailRedirectTo\` passed in options `, }, }, @@ -58,6 +59,7 @@ const INVITE: FormSchema = { - \`{{ .SiteURL }}\` : The URL of the site - \`{{ .Email }}\` : The user's email address - \`{{ .Data }}\` : The user's \`user_metadata\` +- \`{{ .RedirectTo }}\` : The URL of \`redirectTo\` passed in options `, }, }, @@ -92,6 +94,7 @@ const MAGIC_LINK: FormSchema = { - \`{{ .SiteURL }}\` : The URL of the site - \`{{ .Email }}\` : The user's email address - \`{{ .Data }}\` : The user's \`user_metadata\` +- \`{{ .RedirectTo }}\` : The URL of \`emailRedirectTo\` passed in options `, }, }, @@ -127,6 +130,7 @@ const EMAIL_CHANGE: FormSchema = { - \`{{ .Email }}\` : The original user's email address - \`{{ .NewEmail }}\` : The user's new email address - \`{{ .Data }}\` : The user's \`user_metadata\` +- \`{{ .RedirectTo }}\` : The URL of \`emailRedirectTo\` passed in options `, }, }, @@ -161,6 +165,7 @@ const RECOVERY: FormSchema = { - \`{{ .SiteURL }}\` : The URL of the site - \`{{ .Email }}\` : The user's email address - \`{{ .Data }}\` : The user's \`user_metadata\` +- \`{{ .RedirectTo }}\` : The URL of \`redirectTo\` passed in options `, }, }, diff --git a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/PolicyTemplates.tsx b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/PolicyTemplates.tsx index aa4d199eed2..520534f9a50 100644 --- a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/PolicyTemplates.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/PolicyTemplates.tsx @@ -83,10 +83,15 @@ export const PolicyTemplates = ({ icon={
    void onMount?: () => void @@ -39,6 +40,7 @@ const RLSCodeEditor = ({ placeholder, readOnly = false, + disableTabToUsePlaceholder = false, lineNumberStart, onChange = noop, onMount: _onMount = noop, @@ -50,6 +52,7 @@ const RLSCodeEditor = ({ const monaco = useMonaco() const { project } = useProjectContext() + const placeholderId = `monaco-placeholder-${id}` const options: editor.IStandaloneEditorConstructionOptions = { tabSize: 2, fontSize: 13, @@ -70,27 +73,31 @@ const RLSCodeEditor = ({ if (monacoRef !== undefined) monacoRef.current = monaco hasValue.current = editor.createContextKey('hasValue', false) - const placeholderEl = document.querySelector('.monaco-placeholder') as HTMLElement | null - if (placeholderEl && placeholder !== undefined) placeholderEl.style.display = 'block' + const placeholderEl = document.getElementById(placeholderId) as HTMLElement | null + if (placeholderEl && placeholder !== undefined && (value ?? '').trim().length === 0) { + placeholderEl.style.display = 'block' + } - editor.addCommand( - monaco.KeyCode.Tab, - () => { - editor.executeEdits('source', [ - { - // @ts-ignore - identifier: 'add-placeholder', - range: new monaco.Range(1, 1, 1, 1), - text: (placeholder ?? '') - .split('\n\n') - .join('\n') - .replaceAll('*', '') - .replaceAll(' ', ''), - }, - ]) - }, - '!hasValue' - ) + if (!disableTabToUsePlaceholder) { + editor.addCommand( + monaco.KeyCode.Tab, + () => { + editor.executeEdits('source', [ + { + // @ts-ignore + identifier: 'add-placeholder', + range: new monaco.Range(1, 1, 1, 1), + text: (placeholder ?? '') + .split('\n\n') + .join('\n') + .replaceAll('*', '') + .replaceAll(' ', ''), + }, + ]) + }, + '!hasValue' + ) + } editor.focus() @@ -100,7 +107,7 @@ const RLSCodeEditor = ({ const onChangeContent: OnChange = (value) => { hasValue.current.set((value ?? '').length > 0) - const placeholderEl = document.querySelector('.monaco-placeholder') as HTMLElement | null + const placeholderEl = document.getElementById(placeholderId) as HTMLElement | null if (placeholderEl) { if (!value) { placeholderEl.style.display = 'block' @@ -148,6 +155,13 @@ const RLSCodeEditor = ({ } }, [monaco]) + useEffect(() => { + if (value !== undefined && value.trim().length > 0) { + const placeholderEl = document.getElementById(placeholderId) as HTMLElement | null + if (placeholderEl) placeholderEl.style.display = 'none' + } + }, [value]) + return ( <> {placeholder !== undefined && (
    diff --git a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/index.tsx b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/index.tsx index 9f73aa4ced0..fc78e0cbeba 100644 --- a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/index.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/index.tsx @@ -551,14 +551,20 @@ export const AIPolicyEditorPanel = memo(function ({ />
    { + title="Discard changes" + confirmLabel="Discard" + onCancel={() => { setIsClosingPolicyEditorPanel(false) }} - onSelectConfirm={() => { + onConfirm={() => { onSelectCancel() setIsClosingPolicyEditorPanel(false) }} > - -

    - Are you sure you want to close the editor? Any unsaved changes on your policy and - conversations with the Assistant will be lost. -

    -
    +

    + Are you sure you want to close the editor? Any unsaved changes on your policy and + conversations with the Assistant will be lost. +

    ) diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx index 39681d19b41..9c7fd55179b 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx @@ -187,21 +187,19 @@ const PolicyEditorModal = ({
    setIsClosingPolicyEditorModal(false)} - onSelectConfirm={() => { + title="Discard changes" + confirmLabel="Discard" + onCancel={() => setIsClosingPolicyEditorModal(false)} + onConfirm={() => { onSelectCancel() setIsClosingPolicyEditorModal(false) setIsDirty(false) }} > - -

    - There are unsaved changes. Are you sure you want to close the editor? Your changes - will be lost. -

    -
    +

    + There are unsaved changes. Are you sure you want to close the editor? Your changes will + be lost. +

    {view === POLICY_MODAL_VIEWS.SELECTION ? ( { } > + {values['SMTP_HOST'] && values['SMTP_HOST'].endsWith('.gmail.com') && ( + + + Check your SMTP provider + + Not all SMTP providers are designed for the email sending required by + Supabase Auth. It looks like the SMTP provider you entered is designed for + sending personal email messages and not for sending transactional messages. + Although you can ignore this warning, email deliverability may be impacted. + + + )} - @@ -224,35 +224,30 @@ const UserDropdown = ({ setIsDeleteModalOpen(false)} - onSelectConfirm={() => { + title="Confirm to delete" + confirmLabel="Delete" + onCancel={() => setIsDeleteModalOpen(false)} + onConfirm={() => { handleDelete() }} > - -

    - This is permanent! Are you sure you want to delete user {user.email}? -

    -
    +

    + This is permanent! Are you sure you want to delete user {user.email}? +

    setIsDeleteFactorsModalOpen(false)} - onSelectConfirm={() => { + title="Confirm to delete" + confirmLabel="Delete" + onCancel={() => setIsDeleteFactorsModalOpen(false)} + onConfirm={() => { handleDeleteFactors() }} > - -

    - This is permanent! Are you sure you want to delete the user's MFA factors? -

    -
    +

    + This is permanent! Are you sure you want to delete the user's MFA factors? +

    ) diff --git a/apps/studio/components/interfaces/Auth/Users/UsersListItem.tsx b/apps/studio/components/interfaces/Auth/Users/UsersListItem.tsx index f815736197b..f3bea22339a 100644 --- a/apps/studio/components/interfaces/Auth/Users/UsersListItem.tsx +++ b/apps/studio/components/interfaces/Auth/Users/UsersListItem.tsx @@ -40,7 +40,9 @@ const UserListItem = ({ {!user.phone ? '-' : user.phone} - {user?.raw_app_meta_data?.provider} + + {user.is_anonymous ? 'Anonymous' : user?.raw_app_meta_data?.provider} + {createdAt?.format('DD MMM, YYYY HH:mm')} diff --git a/apps/studio/components/interfaces/Auth/Users/UsersListItemSkeleton.tsx b/apps/studio/components/interfaces/Auth/Users/UsersListItemSkeleton.tsx index d3b9bfbdab6..5cc5ba87e15 100644 --- a/apps/studio/components/interfaces/Auth/Users/UsersListItemSkeleton.tsx +++ b/apps/studio/components/interfaces/Auth/Users/UsersListItemSkeleton.tsx @@ -27,7 +27,7 @@ const UsersListItemSkeleton = () => { - diff --git a/apps/studio/components/interfaces/BranchManagement/BranchManagement.tsx b/apps/studio/components/interfaces/BranchManagement/BranchManagement.tsx index 5dfd87fe071..e9983ef50ce 100644 --- a/apps/studio/components/interfaces/BranchManagement/BranchManagement.tsx +++ b/apps/studio/components/interfaces/BranchManagement/BranchManagement.tsx @@ -344,44 +344,28 @@ const BranchManagement = () => { /> onConfirmDisableBranching()} - onSelectCancel={() => setShowDisableBranching(false)} + title="Confirm disable branching for project" + confirmLabel="Confirm disable branching" + confirmLabelLoading="Disabling branching..." + onConfirm={() => onConfirmDisableBranching()} + onCancel={() => setShowDisableBranching(false)} + alert={{ + title: 'This action cannot be undone', + description: + 'All database preview branches will be removed upon disabling branching. You may still re-enable branching again thereafter, but your existing preview branches will not be restored.', + }} > - -
    - - - This action cannot be undone - - All database preview branches will be removed upon disabling branching. You may - still re-enable branching again thereafter, but your existing preview branches will - not be restored. - - -
      -
    • -
      - Before you disable branching, consider: -
        -
      • - Your project no longer requires database previews. -
      • -
      • - None of your database previews are currently being used in any app. -
      • -
      -
      -
    • -
    -
    -
    +

    Before you disable branching, consider:

    +
      +
    • Your project no longer requires database previews.
    • +
    • + None of your database previews are currently being used in any app. +
    • +
    setShowCreateBranch(false)} /> diff --git a/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx b/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx index 2f8471df8b7..e2652c18984 100644 --- a/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx +++ b/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx @@ -1,12 +1,14 @@ import { useParams } from 'common' import dayjs from 'dayjs' -import { GitPullRequest } from 'lucide-react' +import { GitPullRequest, RefreshCw, Trash2 } from 'lucide-react' import Link from 'next/link' -import { PropsWithChildren, ReactNode } from 'react' +import { PropsWithChildren, ReactNode, useState } from 'react' +import toast from 'react-hot-toast' import { useInView } from 'react-intersection-observer' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useBranchQuery } from 'data/branches/branch-query' +import { useBranchResetMutation } from 'data/branches/branch-reset-mutation' import type { Branch } from 'data/branches/branches-query' import { Badge, @@ -19,8 +21,9 @@ import { IconExternalLink, IconMoreVertical, IconShield, - IconTrash, + Modal, } from 'ui' +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import BranchStatusBadge from './BranchStatusBadge' interface BranchManagementSectionProps { @@ -111,6 +114,23 @@ export const BranchRow = ({ } ) + const [showConfirmResetModal, setShowConfirmResetModal] = useState(false) + + const { mutate, isLoading: isResetting } = useBranchResetMutation({ + onSuccess() { + toast.success('Success! Please allow a few seconds for the branch to reset.') + setShowConfirmResetModal(false) + }, + }) + + function onConfirmReset() { + if (!projectRef) { + throw new Error('Invalid project reference') + } + + mutate({ id: branch.id, projectRef }) + } + return (
    @@ -204,16 +224,40 @@ export const BranchRow = ({
    )}
    diff --git a/apps/studio/components/interfaces/Database/Backups/BackupsEmpty.tsx b/apps/studio/components/interfaces/Database/Backups/BackupsEmpty.tsx index 451ab6786a4..263e2cd71ad 100644 --- a/apps/studio/components/interfaces/Database/Backups/BackupsEmpty.tsx +++ b/apps/studio/components/interfaces/Database/Backups/BackupsEmpty.tsx @@ -2,7 +2,7 @@ import { IconInfo } from 'ui' const BackupsEmpty = () => { return ( -
    +

    No backups created yet - check again tomorrow.

    diff --git a/apps/studio/components/interfaces/Database/Backups/BackupsList.tsx b/apps/studio/components/interfaces/Database/Backups/BackupsList.tsx index cf631b5419b..99e30235aa5 100644 --- a/apps/studio/components/interfaces/Database/Backups/BackupsList.tsx +++ b/apps/studio/components/interfaces/Database/Backups/BackupsList.tsx @@ -107,26 +107,22 @@ const BackupsList = () => {
    setSelectedBackup(undefined)} - onSelectConfirm={() => { + onCancel={() => setSelectedBackup(undefined)} + onConfirm={() => { if (selectedBackup === undefined) return console.error('Backup required') restoreFromBackup({ ref: projectRef, backup: selectedBackup }) }} > - -
    -

    - Are you sure you want to restore from - {dayjs(selectedBackup?.inserted_at).format('DD MMM YYYY')}? This will destroy any new - data written since this backup was made. -

    -
    -
    +

    + Are you sure you want to restore from + {dayjs(selectedBackup?.inserted_at).format('DD MMM YYYY')}? This will destroy any new data + written since this backup was made. +

    ) diff --git a/apps/studio/components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx b/apps/studio/components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx index 543d9c03522..5d54690663d 100644 --- a/apps/studio/components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx +++ b/apps/studio/components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx @@ -46,40 +46,32 @@ const DeleteEnumeratedTypeModal = ({ return ( Confirm to delete enumerated type{' '} {selectedEnumeratedType?.name} } - buttonLabel="Confirm delete" - buttonLoadingLabel="Deleting..." - onSelectConfirm={() => onConfirmDeleteType()} - onSelectCancel={onClose} + confirmLabel="Confirm delete" + confirmLabelLoading="Deleting..." + onCancel={onClose} + onConfirm={() => onConfirmDeleteType()} + alert={{ + title: 'This action cannot be undone', + description: + 'You will need to re-create the enumerated type if you want to revert the deletion.', + }} > - -
    - - - This action cannot be undone - - You will need to re-create the enumerated type if you want to revert the deletion. - - -
    - Before deleting this enumerated type, consider: -
      -
    • - This enumerated type is no longer in use in any tables or functions -
    • -
    -
    -
    -
    +

    Before deleting this enumerated type, consider:

    +
      +
    • + This enumerated type is no longer in use in any tables or functions +
    • +
    ) } diff --git a/apps/studio/components/interfaces/Database/Extensions/ExtensionCard.tsx b/apps/studio/components/interfaces/Database/Extensions/ExtensionCard.tsx index 2600bc9d264..820fec90bf2 100644 --- a/apps/studio/components/interfaces/Database/Extensions/ExtensionCard.tsx +++ b/apps/studio/components/interfaces/Database/Extensions/ExtensionCard.tsx @@ -139,17 +139,15 @@ const ExtensionCard = ({ extension }: ExtensionCardProps) => { /> setIsDisableModalOpen(false)} - onSelectConfirm={() => onConfirmDisable()} + title="Confirm to disable extension" + confirmLabel="Disable" + confirmLabelLoading="Disabling" + onCancel={() => setIsDisableModalOpen(false)} + onConfirm={() => onConfirmDisable()} > - -

    - Are you sure you want to turn OFF the "{extension.name}" extension? -

    -
    +

    + Are you sure you want to turn OFF the "{extension.name}" extension? +

    ) diff --git a/apps/studio/components/interfaces/Database/Functions/CreateFunction/index.tsx b/apps/studio/components/interfaces/Database/Functions/CreateFunction/index.tsx index 7a80bf93977..22b26ae53ac 100644 --- a/apps/studio/components/interfaces/Database/Functions/CreateFunction/index.tsx +++ b/apps/studio/components/interfaces/Database/Functions/CreateFunction/index.tsx @@ -405,20 +405,18 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => { ) : null} setIsClosingPanel(false)} - onSelectConfirm={() => { + title="Discard changes" + confirmLabel="Discard" + onCancel={() => setIsClosingPanel(false)} + onConfirm={() => { setIsClosingPanel(false) setVisible(!visible) }} > - -

    - There are unsaved changes. Are you sure you want to close the panel? Your changes will - be lost. -

    -
    +

    + There are unsaved changes. Are you sure you want to close the panel? Your changes will + be lost. +

    diff --git a/apps/studio/components/interfaces/Database/Hooks/EditHookPanel.tsx b/apps/studio/components/interfaces/Database/Hooks/EditHookPanel.tsx index c978ecc60d5..facc120d93e 100644 --- a/apps/studio/components/interfaces/Database/Hooks/EditHookPanel.tsx +++ b/apps/studio/components/interfaces/Database/Hooks/EditHookPanel.tsx @@ -310,21 +310,19 @@ const EditHookPanel = ({ visible, selectedHook, onClose }: EditHookPanelProps) = setIsClosingPanel(false)} - onSelectConfirm={() => { + title="Discard changes" + confirmLabel="Discard" + onCancel={() => setIsClosingPanel(false)} + onConfirm={() => { setIsClosingPanel(false) setIsEdited(false) onClose() }} > - -

    - There are unsaved changes. Are you sure you want to close the panel? Your changes will - be lost. -

    -
    +

    + There are unsaved changes. Are you sure you want to close the panel? Your changes will be + lost. +

    ) diff --git a/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx b/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx index 62a2fcd0390..6a2aabfa437 100644 --- a/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx +++ b/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx @@ -7,7 +7,6 @@ import { Button, IconExternalLink, IconSearch, Input } from 'ui' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import AlertError from 'components/ui/AlertError' -import { FormHeader } from 'components/ui/Forms' import NoSearchResults from 'components/ui/NoSearchResults' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useDatabaseHooksQuery } from 'data/database-triggers/database-triggers-query' @@ -45,95 +44,87 @@ const HooksList = ({ createHook = noop, editHook = noop, deleteHook = noop }: Ho const isPermissionsLoaded = usePermissionsLoaded() return ( - <> +
    - } + value={filterString} + className="w-64" + onChange={(e) => setFilterString(e.target.value)} /> -
    -
    -
    - } - value={filterString} - className="w-64" - onChange={(e) => setFilterString(e.target.value)} - /> -
    - + + + - - - - - {isPermissionsLoaded && !canCreateWebhooks && ( - - - -
    - - You need additional permissions to create webhooks - -
    -
    -
    - )} -
    -
    + Create a new hook + + + {isPermissionsLoaded && !canCreateWebhooks && ( + + + +
    + + You need additional permissions to create webhooks + +
    +
    +
    + )} +
    - - {isLoading && ( -
    - -
    - )} - - {isError && } - - {isSuccess && - (hooks.length <= 0 ? ( - - ) : ( - <> - {filteredHooks.length <= 0 && ( - setFilterString('')} - /> - )} - {filteredHookSchemas.map((schema: any) => ( - - ))} - - ))}
    - + + {isLoading && ( +
    + +
    + )} + + {isError && } + + {isSuccess && + (hooks.length <= 0 ? ( + + ) : ( + <> + {filteredHooks.length <= 0 && ( + setFilterString('')} + /> + )} + {filteredHookSchemas.map((schema: any) => ( + + ))} + + ))} +
    ) } diff --git a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx index d7fa601be4c..db61e85a643 100644 --- a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx +++ b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx @@ -2,6 +2,7 @@ import Link from 'next/link' import { useEffect, useMemo, useState } from 'react' import toast from 'react-hot-toast' +import { SelectValue } from '@ui/components/shadcn/ui/select' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { CodeEditor } from 'components/ui/CodeEditor' import ShimmeringLoader from 'components/ui/ShimmeringLoader' @@ -10,8 +11,19 @@ import { useSchemasQuery } from 'data/database/schemas-query' import { useTableColumnsQuery } from 'data/database/table-columns-query' import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query' import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation' -import { Button, Input, Listbox, SidePanel } from 'ui' +import { + Button, + Input, + SelectContent_Shadcn_, + SelectItem_Shadcn_, + SelectSeparator_Shadcn_, + SelectTrigger_Shadcn_, + SelectValue_Shadcn_, + Select_Shadcn_, + SidePanel, +} from 'ui' import MultiSelect, { MultiSelectOption } from 'ui-patterns/MultiSelect' +import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { INDEX_TYPES } from './Indexes.constants' interface CreateIndexSidePanelProps { @@ -22,7 +34,7 @@ interface CreateIndexSidePanelProps { const CreateIndexSidePanel = ({ visible, onClose }: CreateIndexSidePanelProps) => { const { project } = useProjectContext() const [selectedSchema, setSelectedSchema] = useState('public') - const [selectedEntity, setSelectedEntity] = useState('---') + const [selectedEntity, setSelectedEntity] = useState(undefined) const [selectedColumns, setSelectedColumns] = useState([]) const [selectedIndexType, setSelectedIndexType] = useState(INDEX_TYPES[0].value) @@ -92,14 +104,14 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp useEffect(() => { if (visible) { setSelectedSchema('public') - setSelectedEntity('---') + setSelectedEntity('') setSelectedColumns([]) setSelectedIndexType(INDEX_TYPES[0].value) } }, [visible]) useEffect(() => { - setSelectedEntity('---') + setSelectedEntity('') setSelectedColumns([]) setSelectedIndexType(INDEX_TYPES[0].value) }, [selectedSchema]) @@ -109,6 +121,8 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp setSelectedIndexType(INDEX_TYPES[0].value) }, [selectedEntity]) + const isSelectEntityDisabled = entityTypes.length === 0 + return (
    - - {(schemas ?? []).map((schema) => ( - - {schema.name} - - ))} - - - {entityTypes.length === 0 ? ( -
    -

    Select a table

    - -
    - ) : ( - + - - --- - - {(entityTypes ?? []).map((entity) => ( - - {entity.name} - - ))} - - )} + + {selectedSchema} + + + {(schemas ?? []).map((schema) => ( + + {schema.name} + + ))} + + + - {selectedEntity !== '---' && ( -
    -

    Select up to 32 columns

    + + + + + {selectedEntity} + + + + {(entityTypes ?? []).map((entity) => ( + + {entity.name} + + ))} + + + + + {selectedEntity && ( + {isLoadingTableColumns && } {isSuccessTableColumns && ( )} -
    + )}
    @@ -182,21 +208,43 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp <> - - {INDEX_TYPES.map((index) => ( - -

    {index.name}

    - {index.description.split('\n').map((x, idx) => ( -

    {x}

    + + + + {selectedIndexType} + + + + {INDEX_TYPES.map((index, i) => ( + <> + +
    + {index.name} + {index.description.split('\n').map((x, idx) => ( + + {x} + + ))} +
    +
    + {i < INDEX_TYPES.length - 1 && } + ))} -
    - ))} -
    + + +
    diff --git a/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx b/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx index 08a58863830..14f9af79eaa 100644 --- a/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx +++ b/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx @@ -1,23 +1,10 @@ import { partition, sortBy } from 'lodash' -import Link from 'next/link' -import { useState } from 'react' +import { useEffect, useState } from 'react' import toast from 'react-hot-toast' -import { - AlertDescription_Shadcn_, - AlertTitle_Shadcn_, - Alert_Shadcn_, - Button, - IconAlertCircle, - IconAlertTriangle, - IconExternalLink, - IconSearch, - IconTrash, - Input, - Modal, - SidePanel, -} from 'ui' +import { Button, IconAlertCircle, IconSearch, IconTrash, Input, SidePanel } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' +import { useParams } from 'common' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' @@ -32,13 +19,15 @@ import ProtectedSchemaWarning from '../ProtectedSchemaWarning' import CreateIndexSidePanel from './CreateIndexSidePanel' const Indexes = () => { + const { project } = useProjectContext() + const { schema: urlSchema, table } = useParams() + const [search, setSearch] = useState('') const [selectedSchema, setSelectedSchema] = useState('public') const [showCreateIndex, setShowCreateIndex] = useState(false) const [selectedIndex, setSelectedIndex] = useState() const [selectedIndexToDelete, setSelectedIndexToDelete] = useState() - const { project } = useProjectContext() const { data: allIndexes, refetch: refetchIndexes, @@ -93,38 +82,20 @@ const Indexes = () => { }) } + useEffect(() => { + if (urlSchema !== undefined) { + const schema = schemas?.find((s) => s.name === urlSchema) + if (schema !== undefined) setSelectedSchema(schema.name) + } + }, [urlSchema, isSuccessSchemas]) + + useEffect(() => { + if (table !== undefined) setSearch(table) + }, [table]) + return ( <>
    -
    -
    -

    Database Indexes

    -
    - Improve query performance against your database -
    -
    -
    - - -
    -
    -
    @@ -264,48 +235,41 @@ const Indexes = () => { setShowCreateIndex(false)} /> Confirm to delete index {selectedIndexToDelete?.name} } - buttonLabel="Confirm delete" - buttonLoadingLabel="Deleting..." - onSelectConfirm={() => + confirmLabel="Confirm delete" + confirmLabelLoading="Deleting..." + onConfirm={() => selectedIndexToDelete !== undefined ? onConfirmDeleteIndex(selectedIndexToDelete) : {} } - onSelectCancel={() => setSelectedIndexToDelete(undefined)} + onCancel={() => setSelectedIndexToDelete(undefined)} + alert={{ + title: 'This action cannot be undone', + description: + 'Deleting an index that is still in use will cause queries to slow down, and in some cases causing significant performance issues.', + }} > - -
    - - - This action cannot be undone - - Deleting an index that is still in use will cause queries to slow down, and in some - cases causing significant performance issues. - - -
      -
    • -
      - Before deleting this index, consider: -
        -
      • This index is no longer in use
      • -
      • - The table which the index is on is not currently in use, as dropping an index - requires a short exclusive access lock on the table. -
      • -
      -
      -
    • -
    -
    -
    +
      +
    • +
      + Before deleting this index, consider: +
        +
      • This index is no longer in use
      • +
      • + The table which the index is on is not currently in use, as dropping an index + requires a short exclusive access lock on the table. +
      • +
      +
      +
    • +
    ) diff --git a/apps/studio/components/interfaces/Database/Migrations/Migrations.tsx b/apps/studio/components/interfaces/Database/Migrations/Migrations.tsx index d752098009c..74896cc2b27 100644 --- a/apps/studio/components/interfaces/Database/Migrations/Migrations.tsx +++ b/apps/studio/components/interfaces/Database/Migrations/Migrations.tsx @@ -1,7 +1,7 @@ import dayjs from 'dayjs' import Link from 'next/link' import { useState } from 'react' -import { Alert, Button, IconExternalLink, IconSearch, Input, SidePanel } from 'ui' +import { Alert, Button, IconSearch, Input, SidePanel } from 'ui' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import Table from 'components/to-be-cleaned/Table' @@ -28,131 +28,109 @@ const Migrations = () => { return ( <> -
    -
    -
    -

    Database Migrations

    -
    - History of migrations that have been run on your database -
    -
    -
    - -
    + {isLoading && ( +
    + + +
    + )} - {isLoading && ( -
    - - - +
    + {isError && ( + + + Contact support + + , + ]} + > +

    + Try refreshing your browser, but if the issue persists, please reach out to us via + support. +

    +

    Error: {(error as any)?.message ?? 'Unknown'}

    +
    + )} + {isSuccess && ( +
    + {data.result.length <= 0 && } + + {data.result.length > 0 && ( + <> +
    + setSearch(e.target.value)} + icon={} + /> +
    + + Version + , + Name, + Inserted at (UTC), + , + ]} + body={ + migrations.length > 0 ? ( + migrations.map((migration) => { + // [Joshen] LEFT OFF HERE + const insertedAt = dayjs(migration.version, 'YYYYMMDDHHmmss').format( + 'DD MMM YYYY, HH:mm:ss' + ) + + return ( + + {migration.version} + + {migration?.name ?? 'Name not available'} + + {insertedAt} + + + + + ) + }) + ) : ( + + +

    No results found

    +

    + Your search for "{search}" did not return any results +

    +
    +
    + ) + } + /> + + )} )} - -
    - {isError && ( - - - Contact support - - , - ]} - > -

    - Try refreshing your browser, but if the issue persists, please reach out to us via - support. -

    -

    Error: {(error as any)?.message ?? 'Unknown'}

    -
    - )} - {isSuccess && ( -
    - {data.result.length <= 0 && } - - {data.result.length > 0 && ( - <> -
    - setSearch(e.target.value)} - icon={} - /> -
    -
    - Version - , - Name, - Inserted at (UTC), - , - ]} - body={ - migrations.length > 0 ? ( - migrations.map((migration) => { - // [Joshen] LEFT OFF HERE - const insertedAt = dayjs(migration.version, 'YYYYMMDDHHmmss').format( - 'DD MMM YYYY, HH:mm:ss' - ) - - return ( - - {migration.version} - - {migration?.name ?? 'Name not available'} - - {insertedAt} - - - - - ) - }) - ) : ( - - -

    No results found

    -

    - Your search for "{search}" did not return any results -

    -
    -
    - ) - } - /> - - )} - - )} - setToggleListenEventValue(null)} - onSelectConfirm={() => { + title={`Confirm to toggle sending ${toggleListenEventValue?.event.event.toLowerCase()} events`} + confirmLabel="Confirm" + confirmLabelLoading="Updating" + onCancel={() => setToggleListenEventValue(null)} + onConfirm={() => { toggleListenEvent() }} > - -

    - Are you sure you want to {toggleListenEventValue?.currentStatus ? 'stop' : 'start'}{' '} - sending {toggleListenEventValue?.event.event.toLowerCase()} events for{' '} - {toggleListenEventValue?.publication.name}? -

    -
    +

    + Are you sure you want to {toggleListenEventValue?.currentStatus ? 'stop' : 'start'}{' '} + sending {toggleListenEventValue?.event.event.toLowerCase()} events for{' '} + {toggleListenEventValue?.publication.name}? +

    ) diff --git a/apps/studio/components/interfaces/Database/Roles/RolesList.tsx b/apps/studio/components/interfaces/Database/Roles/RolesList.tsx index 9fc98db4db5..302328cac7c 100644 --- a/apps/studio/components/interfaces/Database/Roles/RolesList.tsx +++ b/apps/studio/components/interfaces/Database/Roles/RolesList.tsx @@ -1,11 +1,11 @@ import * as Tooltip from '@radix-ui/react-tooltip' import { PermissionAction } from '@supabase/shared-types/out/constants' import { partition, sortBy } from 'lodash' +import { Plus, Search, X } from 'lucide-react' import { useState } from 'react' -import { Badge, Button, IconPlus, IconSearch, IconX, Input } from 'ui' +import { Badge, Button, Input } from 'ui' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import { FormHeader } from 'components/ui/Forms' import NoSearchResults from 'components/ui/NoSearchResults' import SparkBar from 'components/ui/SparkBar' import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query' @@ -59,135 +59,128 @@ const RolesList = () => { return ( <> -
    -
    - +
    + } + value={filterString} + onChange={(event: any) => setFilterString(event.target.value)} + actions={ + filterString && ( + + ) + } /> -
    - -
    -
    - } - value={filterString} - onChange={(event: any) => setFilterString(event.target.value)} - actions={ - filterString && ( - - ) - } - /> -
    - -
    - -
    +
    + +
    +
    -
    - - -
    - 0.9 * maxConnectionLimit - ? 'bg-red-800' - : totalActiveConnections > 0.75 * maxConnectionLimit - ? 'bg-amber-900' - : 'bg-green-800' - } - labelTop={ - Number.isInteger(maxConnectionLimit) - ? `${totalActiveConnections}/${maxConnectionLimit}` - : `${totalActiveConnections}` - } - labelBottom="Active connections" - /> -
    -
    +
    +
    + + +
    + 0.9 * maxConnectionLimit + ? 'bg-destructive' + : totalActiveConnections > 0.75 * maxConnectionLimit + ? 'bg-warning' + : undefined + } + labelTop={ + Number.isInteger(maxConnectionLimit) + ? `${totalActiveConnections}/${maxConnectionLimit}` + : `${totalActiveConnections}` + } + labelBottom="Active connections" + /> +
    +
    + + +
    +

    Connections by roles:

    + {rolesWithActiveConnections.map((role) => ( +
    + {role.name}: {role.active_connections} +
    + ))} +
    +
    +
    + + + + + {!canUpdateRoles && (
    -

    Connections by roles:

    - {rolesWithActiveConnections.map((role) => ( -
    - {role.name}: {role.active_connections} -
    - ))} + You need additional permissions to add a new role
    -
    - - - - - {!canUpdateRoles && ( - - -
    - You need additional permissions to add a new role -
    -
    - )} -
    -
    + )} +
    +
    -
    +
    + {supabaseRoles.length > 0 && (

    Roles managed by Supabase

    @@ -196,7 +189,7 @@ const RolesList = () => { {isLoading ? Array.from({ length: 5 }).map((_, i) => ) - : supabaseRoles.map((role, i: number) => ( + : supabaseRoles.map((role) => ( { /> ))}
    + )} + {otherRoles.length > 0 && (

    Other database roles

    @@ -213,7 +208,7 @@ const RolesList = () => { {isLoading ? Array.from({ length: 3 }).map((_, i) => ) - : otherRoles.map((role, i: number) => ( + : otherRoles.map((role) => ( { /> ))}
    -
    - - {filterString.length > 0 && filteredRoles.length === 0 && ( - setFilterString('')} /> )}
    + {filterString.length > 0 && filteredRoles.length === 0 && ( + setFilterString('')} /> + )} + setIsCreatingRole(false)} /> -
    -
    -

    Database Tables

    - - {isLoading ? ( - - ) : ( -

    {selectedTable?.name}

    - )} -
    -
    -
    - {isWrappersEnabled && } -
    + ) : ( + <> + {/* [Joshen] This probably needs to change anyways so dont get too stuck with this */} + {WRAPPERS.map((wrapper, i) => { + const createdWrappers = groupedWrappers[wrapper.handlerName] ?? [] + if (createdWrappers.length > 0) { + return ( + { + if (open !== wrapperName) setOpen(wrapperName) + else setOpen('') + }} + onSelectDelete={setSelectedWrapperToDelete} + /> + ) + } else { + return null + } + })} + + )}
    + ) : ( + + )} - {isLoadingExtensions || isLoading ? ( -
    - -
    - ) : isWrappersEnabled ? ( -
    - {wrappers.length === 0 ? ( -
    -

    No wrappers created yet

    - -
    - ) : ( - <> - {/* [Joshen] This probably needs to change anyways so dont get too stuck with this */} - {WRAPPERS.map((wrapper, i) => { - const createdWrappers = groupedWrappers[wrapper.handlerName] ?? [] - if (createdWrappers.length > 0) { - return ( - { - if (open !== wrapperName) setOpen(wrapperName) - else setOpen('') - }} - onSelectDelete={setSelectedWrapperToDelete} - /> - ) - } else { - return null - } - })} - - )} -
    - ) : ( - - )} -
    setSelectedWrapperToDelete(undefined)} diff --git a/apps/studio/components/interfaces/Database/Wrappers/WrappersDisabledState.tsx b/apps/studio/components/interfaces/Database/Wrappers/WrappersDisabledState.tsx index a7cc80093fa..bff82310924 100644 --- a/apps/studio/components/interfaces/Database/Wrappers/WrappersDisabledState.tsx +++ b/apps/studio/components/interfaces/Database/Wrappers/WrappersDisabledState.tsx @@ -74,7 +74,7 @@ const WrappersDisabledState = () => { return (
    " \\ +-H "Authorization: Bearer USER_TOKEN" \\ -H "Content-Type: application/json" \\ -d '{ "email": "someone@email.com", diff --git a/apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EdgeFunctionSecrets.tsx b/apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EdgeFunctionSecrets.tsx index 53bd9781550..00c93883347 100644 --- a/apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EdgeFunctionSecrets.tsx +++ b/apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EdgeFunctionSecrets.tsx @@ -121,22 +121,20 @@ const EdgeFunctionSecrets = () => { setSelectedSecret(undefined)} - onSelectConfirm={() => { + confirmLabel="Delete secret" + confirmLabelLoading="Deleting secret" + title={`Confirm to delete secret "${selectedSecret?.name}"`} + onCancel={() => setSelectedSecret(undefined)} + onConfirm={() => { if (selectedSecret !== undefined) { deleteSecret({ projectRef, secrets: [selectedSecret.name] }) } }} > - -

    - Before removing this secret, do ensure that none of your edge functions are currently - actively using this secret. This action cannot be undone. -

    -
    +

    + Before removing this secret, do ensure that none of your edge functions are currently + actively using this secret. This action cannot be undone. +

    ) diff --git a/apps/studio/components/interfaces/Home/ProjectList/ProjectCard.tsx b/apps/studio/components/interfaces/Home/ProjectList/ProjectCard.tsx index bfc8edc5481..7834f039f58 100644 --- a/apps/studio/components/interfaces/Home/ProjectList/ProjectCard.tsx +++ b/apps/studio/components/interfaces/Home/ProjectList/ProjectCard.tsx @@ -5,6 +5,7 @@ import type { IntegrationProjectConnection } from 'data/integrations/integration import type { ProjectInfo } from 'data/projects/projects-query' import type { ResourceWarning } from 'data/usage/resource-warnings-query' import { BASE_PATH } from 'lib/constants' +import InlineSVG from 'react-inlinesvg' import { inferProjectStatus } from './ProjectCard.utils' import { ProjectCardStatus } from './ProjectCardStatus' @@ -43,22 +44,22 @@ const ProjectCard = ({ {desc}
    {isVercelIntegrated && ( -
    - +
    )} {isBranchingEnabled && ( -
    +
    )} {isGithubIntegrated && ( <> -
    +

    {githubRepository}

    diff --git a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx index 758c23f4a04..f2ee1a1dba4 100644 --- a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx +++ b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx @@ -13,7 +13,6 @@ import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { usePermissionsQuery } from 'data/permissions/permissions-query' import { ProjectInfo, useProjectsQuery } from 'data/projects/projects-query' import { ResourceWarning, useResourceWarningsQuery } from 'data/usage/resource-warnings-query' -import { useSelectedOrganization } from 'hooks' import { IS_PLATFORM } from 'lib/constants' import { makeRandomString } from 'lib/helpers' import type { Organization, ResponseError } from 'types' @@ -113,7 +112,7 @@ type OrganizationProjectsProps = { } const OrganizationProjects = ({ - organization: { name, slug }, + organization, projects, overdueInvoices, resourceWarnings, @@ -126,7 +125,6 @@ const OrganizationProjects = ({ rewriteHref, search, }: OrganizationProjectsProps) => { - const organization = useSelectedOrganization() const isEmpty = !projects || projects.length === 0 const sortedProjects = [...(projects || [])].sort((a, b) => a.name.localeCompare(b.name)) const filteredProjects = @@ -164,14 +162,35 @@ const OrganizationProjects = ({ if (search.length > 0 && filteredProjects.length === 0) return null return ( -
    +
    -

    {name}

    +

    {organization.name}

    {!!overdueInvoices.length && (
    +
    + )} + {organization?.restriction_status === 'grace_period' && ( +
    + +
    + )} + {organization?.restriction_status === 'grace_period_over' && ( +
    + +
    + )} + {organization?.restriction_status === 'restricted' && ( +
    +
    )} @@ -199,7 +218,7 @@ const OrganizationProjects = ({ />
    ) : isEmpty ? ( - + ) : ( filteredProjects?.map((project) => ( { return ( -
    +

    No projects

    Get started by creating a new project.

    diff --git a/apps/studio/components/interfaces/Integrations/IntegrationConnection.tsx b/apps/studio/components/interfaces/Integrations/IntegrationConnection.tsx index 3f4974ec761..e050d242b16 100644 --- a/apps/studio/components/interfaces/Integrations/IntegrationConnection.tsx +++ b/apps/studio/components/interfaces/Integrations/IntegrationConnection.tsx @@ -137,29 +137,26 @@ const IntegrationConnectionItem = forwardRef - - {type === 'GitHub' && isBranchingEnabled && ( - - - Branching will be disabled for this project - - Deleting this GitHub connection will remove all preview branches on this project, - and also disable branching for {project.name} - - - )} -

    - This action cannot be undone. Are you sure you want to delete this {type} connection? -

    -
    +

    + This action cannot be undone. Are you sure you want to delete this {type} connection? +

    ) diff --git a/apps/studio/components/interfaces/Integrations/Integrations-Vercel.constants.ts b/apps/studio/components/interfaces/Integrations/Integrations-Vercel.constants.ts index f41d20f9616..21ef731872d 100644 --- a/apps/studio/components/interfaces/Integrations/Integrations-Vercel.constants.ts +++ b/apps/studio/components/interfaces/Integrations/Integrations-Vercel.constants.ts @@ -39,6 +39,10 @@ const ENV_VAR_KEYS = { key: 'SUPABASE_SERVICE_ROLE_KEY', type: 'encrypted', }, + SUPABASE_JWT_SECRET: { + key: 'SUPABASE_JWT_SECRET', + type: 'encrypted', + }, NEXT_PUBLIC_SUPABASE_ANON_KEY: { key: 'NEXT_PUBLIC_SUPABASE_ANON_KEY', type: 'encrypted', diff --git a/apps/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx b/apps/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx index f5e5e328ad5..0fb189e20da 100644 --- a/apps/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx +++ b/apps/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx @@ -17,11 +17,12 @@ import { IconUser, } from 'ui' -import { FilterPopover, LogDetailsPanel } from 'components/interfaces/AuditLogs' +import { LogDetailsPanel } from 'components/interfaces/AuditLogs' import { ScaffoldContainerLegacy } from 'components/layouts/Scaffold' import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' import { DatePicker } from 'components/ui/DatePicker' +import { FilterPopover } from 'components/ui/FilterPopover' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { AuditLog, diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingAddress/BillingAddress.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingAddress/BillingAddress.tsx index 454956fb6ec..b7dd9644694 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingAddress/BillingAddress.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingAddress/BillingAddress.tsx @@ -65,7 +65,7 @@ const BillingAddress = () => {
    -

    Billing Address

    +

    Billing Address

    This will be reflected in every upcoming invoice, past invoices are not affected

    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx index adeb36cb37f..2db03ab302a 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx @@ -32,7 +32,7 @@ const BillingBreakdown = () => {
    -

    Billing breakdown

    +

    Billing Breakdown

    Current billing cycle: {billingCycleStart.format('MMM DD')} -{' '} {billingCycleEnd.format('MMM DD')} diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx index 1dbe974b405..d45216904b2 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx @@ -52,7 +52,7 @@ const BillingEmail = () => {

    -

    Email Recipient

    +

    Email Recipient

    All billing correspondence will go to this email

    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingSettings.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingSettings.tsx index a92669de10b..fcdc869f523 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingSettings.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingSettings.tsx @@ -1,13 +1,13 @@ import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' +import { useIsFeatureEnabled } from 'hooks' import BillingAddress from './BillingAddress/BillingAddress' +import BillingBreakdown from './BillingBreakdown/BillingBreakdown' import BillingEmail from './BillingEmail' import CostControl from './CostControl/CostControl' import CreditBalance from './CreditBalance' import PaymentMethods from './PaymentMethods/PaymentMethods' import Subscription from './Subscription/Subscription' import TaxID from './TaxID/TaxID' -import BillingBreakdown from './BillingBreakdown/BillingBreakdown' -import { useIsFeatureEnabled } from 'hooks' const BillingSettings = () => { const { diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/CostControl/CostControl.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/CostControl/CostControl.tsx index b55eab52ee0..1860dda5a0c 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/CostControl/CostControl.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/CostControl/CostControl.tsx @@ -59,7 +59,7 @@ const CostControl = ({}: CostControlProps) => {
    -

    Cost Control

    +

    Cost Control

    Control whether to use beyond your plans included quota

    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx index 3c965b4c071..8dd878640f3 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/CreditBalance.tsx @@ -28,7 +28,7 @@ const CreditBalance = () => {
    -

    Credit balance

    +

    Credit Balance

    {isCredit && You have credits available} {isDebt && Outstanding payments}
    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/PaymentMethods/PaymentMethods.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/PaymentMethods/PaymentMethods.tsx index 546052649a8..6ff7ab6dcc0 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/PaymentMethods/PaymentMethods.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/PaymentMethods/PaymentMethods.tsx @@ -67,7 +67,7 @@ const PaymentMethods = () => {
    -

    Payment methods

    +

    Payment Methods

    After adding a payment method, make sure to mark it as active to use it for billing. You can remove unused cards. @@ -172,10 +172,7 @@ const PaymentMethods = () => { {canUpdatePaymentMethods && !isActive ? ( - diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx new file mode 100644 index 00000000000..26cf4799ddd --- /dev/null +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx @@ -0,0 +1,158 @@ +import dayjs from 'dayjs' +import { ExternalLink } from 'lucide-react' +import Link from 'next/link' + +import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' +import { useOrgUsageQuery } from 'data/usage/org-usage-query' +import { useSelectedOrganization } from 'hooks' +import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui' +import { CriticalIcon, WarningIcon } from 'ui-patterns/Icons/StatusIcons' + +export const Restriction = () => { + const org = useSelectedOrganization() + const { data: usage, isSuccess: isSuccessOrgUsage } = useOrgUsageQuery({ orgSlug: org?.slug }) + const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({ + orgSlug: org?.slug, + }) + + const hasExceededAnyLimits = Boolean( + usage?.usages.find( + (metric) => + !metric.unlimited && metric.capped && metric.usage > (metric?.pricing_free_units ?? 0) + ) + ) + + // don't show any alerts until everything has been fetched + if (!isSuccessOrgUsage || !isSuccessSubscription || !org) { + return null + } + + let shownAlert: 'exceededLimits' | 'gracePeriod' | 'gracePeriodOver' | 'restricted' | null = null + + if (subscription && hasExceededAnyLimits && !org?.restriction_status) { + shownAlert = 'exceededLimits' + } else if (org?.restriction_status === 'grace_period') { + shownAlert = 'gracePeriod' + } else if (org?.restriction_status === 'grace_period_over') { + shownAlert = 'gracePeriodOver' + } else if (org?.restriction_status === 'restricted') { + shownAlert = 'restricted' + } + + if (shownAlert === null) { + return null + } + + return ( + <> + {shownAlert === 'exceededLimits' && ( + + + + + Your organization's usage has exceeded its included quota + + +

    + Your projects can become unresponsive or enter read-only mode.{' '} + {subscription.plan.id === 'free' + ? 'Please upgrade to the Pro plan to ensure that your projects remain available.' + : 'Please disable spend cap to ensure that your projects remain available.'} +

    +
    + + +
    + + + )} + {shownAlert === 'gracePeriod' && ( + + + Your grace period has started. + +

    + Your organization is over its quota. You can continue with projects until your grace + period ends on{' '} + + {dayjs(org.restriction_data['grace_period_end']).format('DD MMM, YYYY')} + + . After that, requests that go over your quota will no longer be served. Reduce your + usage below your plan's quota or upgrade your plan. +

    +
    + + {/* [Joshen] TODO update once docs are live */} + {/* */} +
    +
    +
    + )} + {shownAlert === 'gracePeriodOver' && ( + + + Your grace period is over. + +

    + You have exceeded your plan’s quota in the past and your grace period ended on{' '} + + {dayjs(org.restriction_data['grace_period_end']).format('DD MMM, YYYY')} + + . Service restrictions will apply if your usage is above your quota. If service + restrictions are active, your projects will no longer be able to serve requests. + Reduce your usage below your plan’s quota or upgrade your plan. +

    +
    + + {/* [Joshen] TODO update once docs are live */} + {/* */} +
    +
    +
    + )} + {shownAlert === 'restricted' && ( + + + All services are restricted. + +

    + Your projects are currently under service restrictions and are not able to serve + requests. You have exceeded your plan’s quota and your grace period ended on{' '} + + {dayjs(org.restriction_data['grace_period_end']).format('DD MMM, YYYY')} + + . Upgrade to lift restrictions or wait until your quota refills. +

    +
    + + {/* [Joshen] TODO update once docs are live */} + {/* */} +
    +
    +
    + )} + + ) +} diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx index 19c588edb2c..ad2c6da28df 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx @@ -3,7 +3,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { isArray } from 'lodash' import Link from 'next/link' import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import toast from 'react-hot-toast' import Table from 'components/to-be-cleaned/Table' @@ -36,6 +36,7 @@ import { import DowngradeModal from './DowngradeModal' import EnterpriseCard from './EnterpriseCard' import ExitSurveyModal from './ExitSurveyModal' +import UpgradeSurveyModal from './UpgradeModal' import MembersExceedLimitModal from './MembersExceedLimitModal' import PaymentMethodSelection from './PaymentMethodSelection' @@ -44,7 +45,10 @@ const PlanUpdateSidePanel = () => { const selectedOrganization = useSelectedOrganization() const slug = selectedOrganization?.slug + const originalPlanRef = useRef() + const [showExitSurvey, setShowExitSurvey] = useState(false) + const [showUpgradeSurvey, setShowUpgradeSurvey] = useState(false) const [selectedPaymentMethod, setSelectedPaymentMethod] = useState() const [showDowngradeError, setShowDowngradeError] = useState(false) const [selectedTier, setSelectedTier] = useState<'tier_free' | 'tier_pro' | 'tier_team'>() @@ -69,7 +73,9 @@ const PlanUpdateSidePanel = () => { snap.setPanelKey(undefined) } - const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: slug }) + const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({ + orgSlug: slug, + }) const { data: plans, isLoading: isLoadingPlans } = useOrgPlansQuery({ orgSlug: slug }) const { data: membersExceededLimit } = useFreeProjectLimitCheckQuery({ slug }) const { mutate: updateOrgSubscription, isLoading: isUpdating } = useOrgSubscriptionUpdateMutation( @@ -79,6 +85,7 @@ const PlanUpdateSidePanel = () => { setSelectedTier(undefined) onClose() window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) + setShowUpgradeSurvey(true) }, onError: (error) => { toast.error(`Unable to update subscription: ${error.message}`) @@ -127,6 +134,12 @@ const PlanUpdateSidePanel = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [visible]) + useEffect(() => { + if (visible && isSuccessSubscription) { + originalPlanRef.current = subscription.plan.id + } + }, [visible, isSuccessSubscription]) + const onConfirmDowngrade = () => { setSelectedTier(undefined) if (hasMembersExceedingFreeTierLimit) { @@ -559,6 +572,16 @@ const PlanUpdateSidePanel = () => { if (success) onClose() }} /> + + { + setShowUpgradeSurvey(false) + if (success) onClose() + }} + /> ) } diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx index b2f6ecfe848..db3a0f34162 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx @@ -12,8 +12,8 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import SparkBar from 'components/ui/SparkBar' import { useOrganizationBillingSubscriptionCancelSchedule } from 'data/subscriptions/org-subscription-cancel-schedule-mutation' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' -import { useOrgUsageQuery } from 'data/usage/org-usage-query' import { useFlag } from 'hooks' +import { ExternalLink } from 'lucide-react' import { useOrgSettingsPageStateSnapshot } from 'state/organization-settings' import { Alert, @@ -22,9 +22,9 @@ import { Alert_Shadcn_, Button, IconCalendar, - IconExternalLink, } from 'ui' import ProjectUpdateDisabledTooltip from '../ProjectUpdateDisabledTooltip' +import { Restriction } from '../Restriction' import PlanUpdateSidePanel from './PlanUpdateSidePanel' const Subscription = () => { @@ -40,8 +40,6 @@ const Subscription = () => { isSuccess, } = useOrgSubscriptionQuery({ orgSlug: slug }) - const { data: usage } = useOrgUsageQuery({ orgSlug: slug }) - const { mutate: cancelSubscriptionSchedule, isLoading: cancelSubscriptionScheduleLoading } = useOrganizationBillingSubscriptionCancelSchedule() @@ -54,60 +52,22 @@ const Subscription = () => { const canChangeTier = !projectUpdateDisabled && !['enterprise'].includes(currentPlan?.id ?? '') - const hasExceededAnyLimits = Boolean( - usage?.usages.find( - (metric) => - !metric.unlimited && metric.capped && metric.usage > (metric?.pricing_free_units ?? 0) - ) - ) - return ( <> - {subscription && hasExceededAnyLimits && ( -
    - - - - -
    , - ]} - > -

    - Your projects can become unresponsive or enter read-only mode.{' '} - {subscription.plan.id === 'free' - ? 'Please upgrade to the Pro plan to ensure that your projects remain available.' - : 'Please disable Spend Cap to ensure that your projects remain available.'} -

    - -
    - )} - +
    + +
    -

    Subscription Plan

    +

    Subscription Plan

    More information

    Pricing

    - +
    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx new file mode 100644 index 00000000000..57b10fd0acf --- /dev/null +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx @@ -0,0 +1,127 @@ +import { includes, without } from 'lodash' +import { useReducer, useState } from 'react' +import toast from 'react-hot-toast' + +import { useParams } from 'common' +import { useSendUpgradeFeedbackMutation } from 'data/feedback/upgrade-survey-send' +import type { OrgSubscription } from 'data/subscriptions/types' +import { Input, Modal } from 'ui' +import { generateUpgradeReasons } from '../helpers' + +export interface UpgradeSurveyModalProps { + visible: boolean + originalPlan?: string + subscription?: OrgSubscription + onClose: (success?: boolean) => void +} + +// Upgrade survey is from free plan to pro/teams plan and from pro to teams plan +const UpgradeSurveyModal = ({ + visible, + originalPlan, + subscription, + onClose, +}: UpgradeSurveyModalProps) => { + const { slug } = useParams() + const [message, setMessage] = useState('') + const [selectedReasons, dispatchSelectedReasons] = useReducer(reducer, []) + + const upgradeReasons = generateUpgradeReasons(originalPlan, subscription?.plan.id) + + const { mutate: sendUpgradeSurvey, isLoading: isSubmitting } = useSendUpgradeFeedbackMutation({ + onError: (error) => { + toast.error(`Failed to submit survey: ${error.message}`) + }, + onSuccess: () => { + onClose(true) + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) + }, + }) + + function reducer(state: any, action: any) { + if (includes(state, action.target.value)) { + return without(state, action.target.value) + } else { + return [...state, action.target.value] + } + } + + const onSubmit = async () => { + if (selectedReasons.length === 0) { + return toast.error('Please select at least one reason for upgrading your subscription') + } + sendUpgradeSurvey({ + orgSlug: slug, + prevPlan: originalPlan, + currentPlan: subscription?.plan?.id, + reasons: selectedReasons, + message: message.trim() || undefined, + }) + } + + return ( + <> + + +
    +

    + What reasons motivated your decision to upgrade? Your feedback helps us improve + Supabase as much as we can. +

    +
    +
    + {upgradeReasons.map((option) => { + const active = selectedReasons.find((x) => x === option) + return ( + + ) + })} +
    +
    + setMessage(event.target.value)} + label="Anything else that we can improve on?" + /> +
    +
    +
    +
    +
    + + ) +} + +export default UpgradeSurveyModal diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.constants.ts b/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.constants.ts index 9595d935efb..24fccf80fb8 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.constants.ts +++ b/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.constants.ts @@ -25,6 +25,18 @@ export const TAX_IDS: TaxId[] = [ placeholder: 'ATU12345678', vatPrefix: 'ATU', }, + { + name: 'AD NRT', + code: 'ad_nrt', + country: 'Andorra', + placeholder: 'A-123456-Z', + }, + { + name: 'AR CUIT', + code: 'ar_cuit', + country: 'Argentina', + placeholder: '12-3456789-01', + }, { name: 'AU ABN', code: 'au_abn', @@ -44,6 +56,12 @@ export const TAX_IDS: TaxId[] = [ placeholder: 'BE0123456789', vatPrefix: 'BE', }, + { + name: 'BO TIN', + code: 'bo_tin', + country: 'Bolivia', + placeholder: '123456789', + }, { name: 'BG VAT', code: 'eu_vat', @@ -112,6 +130,24 @@ export const TAX_IDS: TaxId[] = [ country: 'Chile', placeholder: '12.345.678-K', }, + { + name: 'CN TIN', + code: 'cn_tin', + country: 'China', + placeholder: '123456789012345678', + }, + { + name: 'CO NIT', + code: 'co_nit', + country: 'Colombia', + placeholder: '123.456.789-0', + }, + { + name: 'CR TIN', + code: 'cr_tin', + country: 'Costa Rica', + placeholder: '1-234-567890', + }, { name: 'CY VAT', code: 'eu_vat', @@ -140,6 +176,12 @@ export const TAX_IDS: TaxId[] = [ placeholder: 'DK12345678', vatPrefix: 'DK', }, + { + name: 'DO RCN', + code: 'do_rcn', + country: 'Dominican Republic', + placeholder: '123-4567890-1', + }, { name: 'EE VAT', code: 'eu_vat', @@ -258,6 +300,12 @@ export const TAX_IDS: TaxId[] = [ country: 'Japan', placeholder: '1234567891234', }, + { + name: 'KE PIN', + code: 'ke_pin', + country: 'Kenya', + placeholder: 'P000111111A', + }, { name: 'JP RN', code: 'jp_rn', @@ -341,6 +389,18 @@ export const TAX_IDS: TaxId[] = [ country: 'Norway', placeholder: '123456789MVA', }, + { + name: 'PE RUC', + code: 'pe_ruc', + country: 'Peru', + placeholder: '12345678901', + }, + { + name: 'PH TIN', + code: 'ph_tin', + country: 'Philippines', + placeholder: '123456789012', + }, { name: 'NZ GST', code: 'nz_gst', @@ -386,6 +446,12 @@ export const TAX_IDS: TaxId[] = [ country: 'Saudi Arabia', placeholder: '123456789012345', }, + { + name: 'RS PIB', + code: 'rs_pib', + country: 'Serbia', + placeholder: '123456789', + }, { name: 'SE VAT', code: 'eu_vat', @@ -425,6 +491,12 @@ export const TAX_IDS: TaxId[] = [ country: 'Thailand', placeholder: '1234567891234', }, + { + name: 'TR TIN', + code: 'tr_tin', + country: 'Turkey', + placeholder: '0123456789', + }, { name: 'TW VAT', code: 'tw_vat', @@ -456,4 +528,22 @@ export const TAX_IDS: TaxId[] = [ country: 'South Africa', placeholder: '4123456789', }, + { + name: 'UY RUC', + code: 'uy_ruc', + country: 'Uruguay', + placeholder: '123456789012', + }, + { + name: 'VE RIF', + code: 've_rif', + country: 'Venezuela', + placeholder: 'A-12345678-9', + }, + { + name: 'VN TIN', + code: 'vn_tin', + country: 'Vietnam', + placeholder: '1234567890', + }, ] diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.tsx index 66a8ed0bace..ac96aa369f2 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/TaxID/TaxID.tsx @@ -135,7 +135,7 @@ const TaxID = () => {
    -

    Tax ID

    +

    Tax ID

    Add tax ID(s) to have them appear in your invoices. Old invoices are not affected.

    diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts index a2ec7ee44cb..26e088cd649 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts +++ b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts @@ -23,3 +23,29 @@ export const billingMetricUnit = (pricingMetric: PricingMetric) => { return null } } + +export const generateUpgradeReasons = (originalPlan?: string, upgradedPlan?: string) => { + const reasons = [ + 'Current plan limits are not enough for me', + 'I want better customer support from Supabase', + 'I am migrating from a previous project', + ] + + if (originalPlan === undefined || upgradedPlan === undefined) { + reasons.push('None of the above') + return reasons + } + + if (originalPlan === 'free' && upgradedPlan === 'pro') { + reasons.push('Need more compute') + reasons.push( + 'I want access to additional features like daily backups, cost control, Custom Domain and PITR' + ) + } else if (upgradedPlan === 'team') { + reasons.push('I want access to SOC2 and HIPAA compliance') + } + + reasons.push('None of the above') + + return reasons +} diff --git a/apps/studio/components/interfaces/Organization/Documents/SOC2.tsx b/apps/studio/components/interfaces/Organization/Documents/SOC2.tsx index 675fe63790b..c2417c023b8 100644 --- a/apps/studio/components/interfaces/Organization/Documents/SOC2.tsx +++ b/apps/studio/components/interfaces/Organization/Documents/SOC2.tsx @@ -73,53 +73,46 @@ const SOC2 = () => { )} setIsOpen(false)} size="large" - onSelectConfirm={() => { + title="Non-Disclosure Agreement to access Supabase's SOC2 Report" + confirmLabel="I agree" + confirmLabelLoading="Downloading" + onCancel={() => setIsOpen(false)} + onConfirm={() => { if (slug) fetchSOC2(slug) }} > - -
    -
      -
    1. The information that you are about to access is confidential.
    2. +
        +
      1. The information that you are about to access is confidential.
      2. +
      3. + Your access to our SOC 2 materials is governed by confidentiality obligations + contained in the agreement between Supabase, Inc ("Supabase", "we", "our" or "us") and + the Supabase customer that has authorized you to access our platform to obtain this + information (our "Customer"). +
      4. +
      5. + You must ensure that you treat the information in our SOC 2 materials in accordance + with those confidentiality obligations, as communicated to you by the Customer. +
      6. +
      7. + By clicking "I agree" below or otherwise accessing our SOC 2 materials, you: +
          +
        1. acknowledge that you have read and understood this Confidentiality Notice;
        2. - Your access to our SOC 2 materials is governed by confidentiality obligations - contained in the agreement between Supabase, Inc ("Supabase", "we", "our" or "us") - and the Supabase customer that has authorized you to access our platform to obtain - this information (our "Customer"). -
        3. -
        4. - You must ensure that you treat the information in our SOC 2 materials in - accordance with those confidentiality obligations, as communicated to you by the - Customer. -
        5. -
        6. - By clicking "I agree" below or otherwise accessing our SOC 2 materials, you: -
            -
          1. - acknowledge that you have read and understood this Confidentiality Notice; -
          2. -
          3. - confirm that you have been authorized by the Customer to access this - information, and your use of our SOC 2 materials is subject to the - confidentiality obligations owed by the Customer to us. -
          4. -
          -
        7. -
        8. - This Confidentiality Notice does not substitute or supersede any agreement between - us and the Customer, or any internal rules or policies that the Customer requires - you to comply with in your access to and use of confidential information. However, - your failure to comply with this Confidentiality Notice may be used to determine - whether the Customer has complied with its confidentiality obligations to us. + confirm that you have been authorized by the Customer to access this information, + and your use of our SOC 2 materials is subject to the confidentiality obligations + owed by the Customer to us.
        -
    -
    + +
  • + This Confidentiality Notice does not substitute or supersede any agreement between us + and the Customer, or any internal rules or policies that the Customer requires you to + comply with in your access to and use of confidential information. However, your + failure to comply with this Confidentiality Notice may be used to determine whether + the Customer has complied with its confidentiality obligations to us. +
  • +
    diff --git a/apps/studio/components/interfaces/Organization/Documents/TIA.tsx b/apps/studio/components/interfaces/Organization/Documents/TIA.tsx index e1cd3a42075..a869a73d753 100644 --- a/apps/studio/components/interfaces/Organization/Documents/TIA.tsx +++ b/apps/studio/components/interfaces/Organization/Documents/TIA.tsx @@ -19,7 +19,7 @@ const TIA = () => { { <>

    Create a new organization

    @@ -361,7 +360,7 @@ const NewOrgForm = ({ onPaymentMethodReset }: NewOrgFormProps) => { icon={} onClick={() => resetPaymentMethod()} disabled={newOrgLoading} - className="hover:border-gray-500" + className="hover:border-muted" />
    diff --git a/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx b/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx index 0aefed076b3..3ce18b3a6ef 100644 --- a/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx +++ b/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx @@ -1,5 +1,5 @@ import Link from 'next/link' -import { Button, IconAlertCircle } from 'ui' +import { Admonition, Button, IconAlertCircle } from 'ui' import InformationBox from 'components/ui/InformationBox' import type { MemberWithFreeProjectLimit } from 'data/organizations/free-project-limit-check-query' @@ -14,8 +14,38 @@ const FreeProjectLimitWarning = ({ orgSlug, }: FreeProjectLimitWarningProps) => { return ( -
    - + +

    + The following members have reached their maximum limits for the number of active free + plan projects within organizations where they are an administrator or owner: +

    +
      + {membersExceededLimit.map((member, idx: number) => ( +
    • + {member.username || member.primary_email} (Limit: {member.free_project_limit} free + projects) +
    • + ))} +
    +

    + These members will need to either delete, pause, or upgrade one or more of these + projects before you're able to create a free project within this organization. +

    + +
    + +
    +
    + } + > + {/* } defaultVisibility={true} hideCollapse @@ -46,8 +76,8 @@ const FreeProjectLimitWarning = ({
    } - /> -
    + /> */} + ) } diff --git a/apps/studio/components/interfaces/Organization/TeamSettings/MemberActions.tsx b/apps/studio/components/interfaces/Organization/TeamSettings/MemberActions.tsx index 3d0dc8ea63a..e905e0ff003 100644 --- a/apps/studio/components/interfaces/Organization/TeamSettings/MemberActions.tsx +++ b/apps/studio/components/interfaces/Organization/TeamSettings/MemberActions.tsx @@ -190,18 +190,16 @@ const MemberActions = ({ member, roles }: MemberActionsProps) => { setIsDeleteModalOpen(false)} - onSelectConfirm={() => { + title="Confirm to remove" + confirmLabel="Remove" + onCancel={() => setIsDeleteModalOpen(false)} + onConfirm={() => { handleMemberDelete() }} > - -

    - This is permanent! Are you sure you want to remove {member.primary_email} -

    -
    +

    + This is permanent! Are you sure you want to remove {member.primary_email} +

    ) diff --git a/apps/studio/components/interfaces/Organization/TeamSettings/TeamSettings.tsx b/apps/studio/components/interfaces/Organization/TeamSettings/TeamSettings.tsx index cebaac3d4f0..7c48c266479 100644 --- a/apps/studio/components/interfaces/Organization/TeamSettings/TeamSettings.tsx +++ b/apps/studio/components/interfaces/Organization/TeamSettings/TeamSettings.tsx @@ -143,18 +143,16 @@ const TeamSettings = () => { setIsLeaveTeamModalOpen(false)} - onSelectConfirm={() => { + title="Are you sure?" + confirmLabel="Leave" + onCancel={() => setIsLeaveTeamModalOpen(false)} + onConfirm={() => { leaveTeam() }} > - -

    - Are you sure you want to leave this organization? This is permanent. -

    -
    +

    + Are you sure you want to leave this organization? This is permanent. +

    ) diff --git a/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx b/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx index d4e6a4708ed..ef3afbb64ac 100644 --- a/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx @@ -82,11 +82,13 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ { key: EgressType.DATABASE, name: 'Database Egress', color: 'green' }, { key: EgressType.STORAGE, name: 'Storage Egress', color: 'blue' }, { key: EgressType.REALTIME, name: 'Realtime Egress', color: 'orange' }, + { key: EgressType.FUNCTIONS, name: 'Functions Egress', color: 'purple' }, + { key: EgressType.SUPAVISOR, name: 'Supavisor Egress', color: 'red' }, ], name: 'Total Egress', unit: 'bytes', description: - 'Contains any outgoing traffic (egress) from your database.\nBilling is based on the total sum of egress in GB throughout your billing period.', + 'Contains any outgoing traffic (includes Database, Storage, Realtime, Auth, API, Edge Functions, Supavisor) from your database.\nBilling is based on the total sum of egress in GB throughout your billing period.', chartDescription: 'The data refreshes every 24 hours.', }, ], diff --git a/apps/studio/components/interfaces/Organization/Usage/Usage.tsx b/apps/studio/components/interfaces/Organization/Usage/Usage.tsx index f9dae822e37..fb0501db851 100644 --- a/apps/studio/components/interfaces/Organization/Usage/Usage.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/Usage.tsx @@ -10,15 +10,15 @@ import InformationBox from 'components/ui/InformationBox' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useProjectsQuery } from 'data/projects/projects-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' -import { useOrgUsageQuery } from 'data/usage/org-usage-query' import { useSelectedOrganization } from 'hooks' import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from 'lib/constants/metrics' import Link from 'next/link' -import { Alert, Button, IconExternalLink, IconInfo, Listbox } from 'ui' +import { Button, IconExternalLink, IconInfo, Listbox } from 'ui' +import { Restriction } from '../BillingSettings/Restriction' import Activity from './Activity' import Bandwidth from './Bandwidth' -import SizeAndCounts from './SizeAndCounts' import Compute from './Compute' +import SizeAndCounts from './SizeAndCounts' import TotalUsage from './TotalUsage' const Usage = () => { @@ -36,8 +36,6 @@ const Usage = () => { isSuccess: isSuccessSubscription, } = useOrgSubscriptionQuery({ orgSlug: slug }) - const { data: usage } = useOrgUsageQuery({ orgSlug: slug }) - const orgProjects = projects?.filter((project) => project.organization_id === organization?.id) useEffect(() => { @@ -94,13 +92,6 @@ const Usage = () => { ? orgProjects?.find((it) => it.ref === selectedProjectRef) : undefined - const hasExceededAnyLimits = Boolean( - usage?.usages.find( - (metric) => - !metric.unlimited && metric.capped && metric.usage > (metric?.pricing_free_units ?? 0) - ) - ) - return ( <> @@ -170,33 +161,7 @@ const Usage = () => {
    - {!selectedProject && subscription && hasExceededAnyLimits && ( - - - - {subscription.plan.id === 'free' ? 'Upgrade plan' : 'Change spend cap'} - - , - ]} - > - Your projects can become unresponsive or enter read-only mode.{' '} - {subscription.plan.id === 'free' - ? 'Please upgrade to the Pro plan to ensure that your projects remain available.' - : 'Please disable spend cap to ensure that your projects remain available.'} - - - )} - - {selectedProjectRef && ( + {selectedProjectRef ? ( { icon={} /> + ) : ( + + + )} { + const { ref: projectRef } = useParams() + const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] + const hooks = queriesFactory(config.queries, projectRef ?? 'default') + + const queryHitRate = hooks.queryHitRate() + const indexHitRate = queryHitRate.data?.[0]?.ratio + const tableHitRate = queryHitRate.data?.[1]?.ratio + const showIndexWarning = + indexHitRate && tableHitRate && (indexHitRate <= 0.99 || tableHitRate <= 0.99) + + const checkAlert = + const warnAlert = + const dangerAlert = + + return ( + + + +
    + Index Efficiency + {showIndexWarning ? warnAlert : checkAlert} +
    +
    + + {!isLoading && queryHitRate && ( +
    +
    +
    +

    Index Hit Rate

    +
    + {indexHitRate >= 0.99 + ? checkAlert + : indexHitRate >= 0.95 + ? warnAlert + : dangerAlert} +
    + + {queryHitRate?.data && (queryHitRate?.data[0]?.ratio * 100).toFixed(2)} + + % +
    +
    +
    + +
    + {queryHitRate?.data![1]?.name == 'table hit rate' && 'Table Hit Rate'} +
    + {tableHitRate >= 0.99 + ? checkAlert + : tableHitRate >= 0.95 + ? warnAlert + : dangerAlert} +
    + + {queryHitRate?.data && (queryHitRate?.data[1]?.ratio * 100).toFixed(2)} + + % +
    +
    +
    +
    + +

    + For best performance, ensure that the cache hit rate ratios above 99%.
    {' '} + Consider upgrading to an instance with more memory if the ratios dip below 95%. +

    +
    + )} +
    +
    +
    + ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.tsx new file mode 100644 index 00000000000..3f9b663f2a6 --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.tsx @@ -0,0 +1,236 @@ +import { useRouter } from 'next/router' + +import Table from 'components/to-be-cleaned/Table' +import { DbQueryHook } from 'hooks/analytics/useDbQuery' +import { Tabs } from 'ui' +import { Markdown } from '../Markdown' +import ReportQueryPerformanceTableRow from '../Reports/ReportQueryPerformanceTableRow' +import { PresetHookResult } from '../Reports/Reports.utils' +import { QueryPerformanceFilterBar } from './QueryPerformanceFilterBar' +import { QueryPerformanceLoadingRow } from './QueryPerformanceLoadingRow' +import { ResetAnalysisNotice } from './ResetAnalysisNotice' + +type QueryPerformancePreset = 'time' | 'frequent' | 'slowest' + +const panelClassNames = 'text-sm max-w-none flex flex-col gap-4' + +const TimeConsumingHelperText = `This table lists queries ordered by their cumulative total execution time. + +It displays the total time a query has spent running and the proportion of total execution time the query has consumed. +` + +const MostFrequentHelperText = `This table lists queries in order of their execution count, providing insights into the most frequently executed queries. + +Pay attention to queries with high max_time or mean_time values that are called frequently, as they may benefit from optimization. +` + +const SlowestExecutionHelperText = `This table lists queries ordered by their maximum execution time. It shows outliers with high execution times. + +Look for queries with high or mean execution times as these are often good candidates for optimization. +` + +interface QueryPerformanceProps { + queryHitRate: PresetHookResult + queryPerformanceQuery: DbQueryHook +} + +export const QueryPerformance = ({ + queryHitRate, + queryPerformanceQuery, +}: QueryPerformanceProps) => { + const router = useRouter() + const isLoading = [queryPerformanceQuery.isLoading, queryHitRate.isLoading].every( + (value) => value + ) + + const handleRefresh = async () => { + queryPerformanceQuery.runQuery() + queryHitRate.runQuery() + } + + return ( + { + // To reset the search and sort query params when switching tabs + const { sort, search, ...rest } = router.query + router.push({ + ...router, + query: { + ...rest, + preset: e, + }, + }) + }} + > + +
    + + +
    + +
    + Role + Query + Calls + Time Consumed + Total Latency + + } + body={ + !queryPerformanceQuery.isLoading ? ( + queryPerformanceQuery?.data?.map((item, i) => { + return ( + + + {item.rolname} + + +

    {item.query}

    +
    + {item.calls} + {item.prop_total_time} + + {item.total_time.toFixed(2)}ms + +
    + ) + }) + ) : ( + + ) + } + /> + + + + +
    + + +
    + +
    + Role + Query + Avg. Roles + Calls + Max Time + Mean Time + Min Time + Total Latency + + } + body={ + queryPerformanceQuery.isLoading ? ( + + ) : ( + queryPerformanceQuery.data?.map((item, i) => { + return ( + + + {item.rolname} + + +

    {item.query}

    +
    + {item.avg_rows} + {item.calls} + + {item.max_time?.toFixed(2)}ms + + + {item.mean_time?.toFixed(2)}ms + + + {item.min_time?.toFixed(2)}ms + + + {item.total_time?.toFixed(2)}ms + +
    + ) + }) + ) + } + /> + + + + +
    + + +
    + +
    + Role + Query + Avg Rows + Calls + Max Time + Mean Time + Min Time + Total Latency + + } + body={ + queryPerformanceQuery.isLoading ? ( + + ) : ( + queryPerformanceQuery.data?.map((item, i) => { + return ( + + + {item.rolname} + + +

    {item.query}

    +
    + {item.avg_rows} + {item.calls} + {item.max_time?.toFixed(2)}ms + {item.mean_time?.toFixed(2)}ms + {item.min_time?.toFixed(2)}ms + {item.total_time?.toFixed(2)}ms +
    + ) + }) + ) + } + /> + + + + + ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx new file mode 100644 index 00000000000..ad69fbb90c0 --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx @@ -0,0 +1,133 @@ +import { ArrowDown, ArrowUp, RefreshCw } from 'lucide-react' +import { useRouter } from 'next/router' +import { useState } from 'react' + +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' +import { FilterPopover } from 'components/ui/FilterPopover' +import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query' +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuTrigger, +} from 'ui' +import { TextSearchPopover } from './TextSearchPopover' + +export const QueryPerformanceFilterBar = ({ + isLoading, + onRefreshClick, +}: { + isLoading: boolean + onRefreshClick: () => void +}) => { + const router = useRouter() + const { project } = useProjectContext() + const defaultSearchQueryValue = router.query.search ? String(router.query.search) : '' + const defaultSortByValue = router.query.sort ? String(router.query.sort) : 'lat_desc' + const defaultFilterRoles = router.query.roles ? (router.query.roles as string[]) : [] + + const [sortByValue, setSortByValue] = useState(defaultSortByValue) + const [searchInputVal, setSearchInputVal] = useState(defaultSearchQueryValue) + const [filters, setFilters] = useState<{ roles: string[]; query: string }>({ + roles: typeof defaultFilterRoles === 'string' ? [defaultFilterRoles] : defaultFilterRoles, + query: '', + }) + + const { data, isLoading: isLoadingRoles } = useDatabaseRolesQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + }) + const roles = (data ?? []).sort((a, b) => a.name.localeCompare(b.name)) + + function getSortButtonLabel() { + const sort = router.query.sort as 'lat_desc' | 'lat_asc' + + if (sort === 'lat_desc') { + return 'Sorted by latency - high to low' + } else { + return 'Sorted by latency - low to high' + } + } + + const onSearchQueryChange = (value: string) => { + setSearchInputVal(value) + + if (!value || typeof value !== 'string') { + // if user has deleted the search query, remove it from the url + const { search, ...rest } = router.query + router.push({ ...router, query: { ...rest } }) + } else { + router.push({ ...router, query: { ...router.query, search: value } }) + } + } + + const onFilterRolesChange = (roles: string[]) => { + setFilters({ ...filters, roles }) + router.push({ ...router, query: { ...router.query, roles } }) + } + + const onSortChange = (sort: string) => { + setSortByValue(sort) + router.push({ ...router, query: { ...router.query, sort } }) + } + + const ButtonIcon = sortByValue === 'lat_desc' ? ArrowDown : ArrowUp + + return ( +
    +
    +
    +

    Filter by

    + + +
    +
    + + + + + + + + Sort by latency - high to low + + + Sort by latency - low to high + + + + +
    + + +
    + ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceLoadingRow.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceLoadingRow.tsx new file mode 100644 index 00000000000..6bd24ccba31 --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceLoadingRow.tsx @@ -0,0 +1,17 @@ +import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' + +export const QueryPerformanceLoadingRow = ({ colSpan }: { colSpan: number }) => { + return ( + <> + {Array(4) + .fill('') + .map((_, i) => ( +
    + + + ))} + + ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/ResetAnalysisNotice.tsx b/apps/studio/components/interfaces/QueryPerformance/ResetAnalysisNotice.tsx new file mode 100644 index 00000000000..44df82f2578 --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/ResetAnalysisNotice.tsx @@ -0,0 +1,53 @@ +import { useState } from 'react' +import toast from 'react-hot-toast' + +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' +import { executeSql } from 'data/sql/execute-sql-query' +import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui' +import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog' + +export const ResetAnalysisNotice = ({ handleRefresh }: { handleRefresh: () => void }) => { + const { project } = useProjectContext() + const [showResetgPgStatStatements, setShowResetgPgStatStatements] = useState(false) + + return ( + <> + + + Consider resetting the analysis after optimizing any queries + + + This will ensure that the performance metrics are updated with the latest changes + + + + + setShowResetgPgStatStatements(false)} + onSelectConfirm={async () => { + try { + await executeSql({ + projectRef: project?.ref, + connectionString: project?.connectionString, + sql: `SELECT pg_stat_statements_reset();`, + }) + handleRefresh() + setShowResetgPgStatStatements(false) + } catch (error: any) { + toast.error(`Failed to reset analysis: ${error.message}`) + } + }} + /> + + ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/TextSearchPopover.tsx b/apps/studio/components/interfaces/QueryPerformance/TextSearchPopover.tsx new file mode 100644 index 00000000000..737faea9b3d --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/TextSearchPopover.tsx @@ -0,0 +1,70 @@ +import { useState } from 'react' +import { + Button, + PopoverContent_Shadcn_, + PopoverTrigger_Shadcn_, + Popover_Shadcn_, + TextArea_Shadcn_, +} from 'ui' + +interface TextSearchPopoverProps { + name: string + value: string + onSaveText: (value: string) => void +} + +export const TextSearchPopover = ({ name, value = '', onSaveText }: TextSearchPopoverProps) => { + const [open, setOpen] = useState(false) + const [search, setSearch] = useState(value) + + return ( + + + + + +
    + setSearch(event.target.value)} + rows={4} + className="text-xs font-mono tracking-tight" + placeholder="Search for a query" + /> +
    +
    + + +
    +
    +
    + ) +} diff --git a/apps/studio/components/interfaces/Realtime/Inspector/ApplyConfigModal.tsx b/apps/studio/components/interfaces/Realtime/Inspector/ApplyConfigModal.tsx deleted file mode 100644 index 45cdf42973c..00000000000 --- a/apps/studio/components/interfaces/Realtime/Inspector/ApplyConfigModal.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Modal } from 'ui' - -import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' - -interface ApplyConfigModalProps { - visible: boolean - onSelectCancel: () => void - onSelectConfirm: () => void -} - -export const ApplyConfigModal = (props: ApplyConfigModalProps) => { - return ( - - -
    -

    -

    - The realtime inspector will clear currently collected messages and start listening for - new messages matching the updated filters. -

    -
    -
    -
    - ) -} diff --git a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx index f0d5a1accfc..62d4c522a09 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx @@ -18,10 +18,10 @@ import { } from 'ui' import Telemetry from 'lib/telemetry' -import { ApplyConfigModal } from '../ApplyConfigModal' import { RealtimeConfig } from '../useRealtimeMessages' import { FilterSchema } from './FilterSchema' import { FilterTable } from './FilterTable' +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' interface RealtimeFilterPopoverProps { config: RealtimeConfig @@ -194,10 +194,14 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter - setApplyConfigOpen(false)} - onSelectConfirm={() => { + onCancel={() => setApplyConfigOpen(false)} + onConfirm={() => { Telemetry.sendEvent( { category: 'realtime_inspector', @@ -211,7 +215,12 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter setApplyConfigOpen(false) setOpen(false) }} - /> + > +

    + The realtime inspector will clear currently collected messages and start listening for new + messages matching the updated filters. +

    + ) } diff --git a/apps/studio/components/interfaces/Reports/ReportHeader.tsx b/apps/studio/components/interfaces/Reports/ReportHeader.tsx index 39a68e44057..65eee3aefe3 100644 --- a/apps/studio/components/interfaces/Reports/ReportHeader.tsx +++ b/apps/studio/components/interfaces/Reports/ReportHeader.tsx @@ -2,11 +2,9 @@ import { Button, IconRefreshCw } from 'ui' interface Props { title: string - onRefresh: () => void - isLoading: boolean } -const ReportHeader: React.FC = ({ title, onRefresh, isLoading }) => ( +const ReportHeader: React.FC = ({ title }) => (

    {title}

    diff --git a/apps/studio/components/interfaces/Reports/ReportLints.utils.tsx b/apps/studio/components/interfaces/Reports/ReportLints.utils.tsx new file mode 100644 index 00000000000..14e26da19fb --- /dev/null +++ b/apps/studio/components/interfaces/Reports/ReportLints.utils.tsx @@ -0,0 +1,104 @@ +import { LINT_TYPES, Lint } from 'data/lint/lint-query' +import Link from 'next/link' +import { Button } from 'ui' + +const assertUnreachable = (n: never) => { + console.error('Unhandled lint type', n) +} + +export function getHumanReadableTitle(title: LINT_TYPES) { + switch (title) { + case 'unindexed_foreign_keys': + return 'Unindexed foreign keys' + case 'auth_users_exposed': + return 'Exposed Auth Users' + case 'auth_rls_initplan': + return 'Auth RLS Initialization Plan' + case 'no_primary_key': + return 'No Primary Key' + case 'unused_index': + return 'Unused Index' + case 'multiple_permissive_policies': + return 'Multiple Permissive Policies' + default: + assertUnreachable(title) + throw new Error('This case should never be reached') + } +} + +export const LintCTA = ({ + title, + projectRef, + metadata, +}: { + title: LINT_TYPES + projectRef: string + metadata: Lint['metadata'] +}) => { + switch (title) { + case 'unindexed_foreign_keys': + return ( + + ) + + case 'auth_users_exposed': + return ( + + ) + case 'auth_rls_initplan': + return ( + + ) + case 'no_primary_key': + return ( + + ) + case 'unused_index': + return ( + + ) + case 'multiple_permissive_policies': + return ( + + ) + default: + assertUnreachable(title) + return <> + } +} diff --git a/apps/studio/components/interfaces/Reports/ReportLintsTableRow.tsx b/apps/studio/components/interfaces/Reports/ReportLintsTableRow.tsx new file mode 100644 index 00000000000..7d31413a126 --- /dev/null +++ b/apps/studio/components/interfaces/Reports/ReportLintsTableRow.tsx @@ -0,0 +1,170 @@ +import { Eye, EyeIcon, EyeOff, HelpCircle, Table2 } from 'lucide-react' +import { useState } from 'react' + +import { useParams } from 'common' +import Table from 'components/to-be-cleaned/Table' +import { LINT_TYPES, Lint } from 'data/lint/lint-query' +import { useLocalStorageQuery } from 'hooks' +import { LOCAL_STORAGE_KEYS } from 'lib/constants' +import { + Badge, + Button, + Modal, + TooltipContent_Shadcn_, + TooltipTrigger_Shadcn_, + Tooltip_Shadcn_, +} from 'ui' +import { Markdown } from '../Markdown' +import { LintCTA, getHumanReadableTitle } from './ReportLints.utils' + +type ReportLintsTableRowProps = { + lint: Lint +} + +const ReportLintsTableRow = ({ lint }: ReportLintsTableRowProps) => { + const { ref } = useParams() + const [selectedLint, setSelectedLint] = useState(null) + + const [lintIgnoreList, setLintIgnoreList] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.PROJECT_LINT_IGNORE_LIST, + [] + ) + const isIgnored = lintIgnoreList.includes(lint.cache_key) + + // if the lint type can't be handled (there's no CTA text defined), don't render it + if (!LINT_TYPES.includes(lint.name)) { + return null + } + + const toggleLintIgnore = () => { + let currentIgnoreList = [] + const cacheKey = lint.cache_key + + // Check if the cacheKey exists in the array and ignore or unignore it + const index = lintIgnoreList.indexOf(cacheKey) + if (index !== -1) { + currentIgnoreList = lintIgnoreList.filter((l) => l !== cacheKey) + } else { + currentIgnoreList = lintIgnoreList.concat(cacheKey) + } + setLintIgnoreList(currentIgnoreList) + setSelectedLint(null) + } + + return ( + <> + + + + {lint.level} + + + + +
    +
    +

    {getHumanReadableTitle(lint.name)}

    + + + + + + {lint.description} + + +
    + + {(lint.metadata?.type === 'table' || lint.metadata?.type === 'view') && ( +
    + {lint.metadata?.schema && ( +
    +

    schema

    +

    {lint.metadata?.schema}

    +
    + )} +
    + {lint.metadata?.type === 'table' && ( + + )} + {lint.metadata?.type === 'view' && ( + + )} +

    {lint.metadata?.name}

    +
    +
    + )} +
    + +
    + + +
    + + + +
    +
    + + setSelectedLint(null)} + onConfirm={() => toggleLintIgnore()} + header={

    Confirm to {isIgnored ? 'unignore' : 'ignore'} this lint

    } + > +
    + +

    + {isIgnored + ? 'Unignoring this lint will remove it from the Ignored Issues list. It will move it back to the main list above.' + : 'Ignoring this lint will remove it from the main list. It will still be visible in the Ignored Issues list below.'} +

    +
    +
    +
    + + ) +} + +export default ReportLintsTableRow diff --git a/apps/studio/components/interfaces/Reports/Reports.queries.ts b/apps/studio/components/interfaces/Reports/Reports.queries.ts index a20c94b481b..1f943b04e29 100644 --- a/apps/studio/components/interfaces/Reports/Reports.queries.ts +++ b/apps/studio/components/interfaces/Reports/Reports.queries.ts @@ -6,11 +6,13 @@ type QueryPerformanceQueryOpts = { searchQuery: string preset: 'mostFrequentlyInvoked' | 'mostTimeConsuming' | 'slowestExecutionTime' | 'queryHitRate' orderBy: string | 'lat_asc' | 'lat_desc' + roles?: string[] } export const useQueryPerformanceQuery = ({ preset, orderBy, searchQuery, + roles, }: QueryPerformanceQueryOpts) => { const queryPerfQueries = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] const baseSQL = queryPerfQueries.queries[preset] @@ -20,9 +22,15 @@ export const useQueryPerformanceQuery = ({ orderBy = 'lat_desc' } - const whereSql = searchQuery - ? `WHERE auth.rolname ~ '${searchQuery}' OR statements.query ~ '${searchQuery}'` - : '' + const whereSql = [ + roles !== undefined && roles.length > 0 + ? `WHERE auth.rolname in (${roles.map((r) => `'${r}'`).join(', ')})` + : '', + searchQuery.length > 0 ? `statements.query ~ '${searchQuery}'` : '', + ] + .filter((x) => x.length > 0) + .join(' OR ') + const orderBySql = orderBy === 'lat_asc' ? 'ORDER BY total_time asc' : 'ORDER BY total_time desc' const sql = baseSQL.sql([], whereSql, orderBySql) diff --git a/apps/studio/components/interfaces/Reports/Reports.utils.tsx b/apps/studio/components/interfaces/Reports/Reports.utils.tsx index cbf86b4693c..eede5de73bc 100644 --- a/apps/studio/components/interfaces/Reports/Reports.utils.tsx +++ b/apps/studio/components/interfaces/Reports/Reports.utils.tsx @@ -10,7 +10,7 @@ export const queryParamsToObject = (params: string) => { } // generate hooks based on preset config -type PresetHookResult = LogsQueryHook | DbQueryHook +export type PresetHookResult = LogsQueryHook | DbQueryHook type PresetHooks = Record PresetHookResult> export const queriesFactory = ( diff --git a/apps/studio/components/interfaces/SQLEditor/DownloadSnippetModal.tsx b/apps/studio/components/interfaces/SQLEditor/DownloadSnippetModal.tsx index 2d0c335907c..db3651b251e 100644 --- a/apps/studio/components/interfaces/SQLEditor/DownloadSnippetModal.tsx +++ b/apps/studio/components/interfaces/SQLEditor/DownloadSnippetModal.tsx @@ -78,7 +78,7 @@ const DownloadSnippetModal = ({ id, ...props }: DownloadSnippetModalProps) => { width={75} options={['CLI', 'NPM']} activeOption={selectedView} - borderOverride="border-gray-100" + borderOverride="border-muted" onClickOption={() => selectedView === 'CLI' ? setSelectedView('NPM') : setSelectedView('CLI') } diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/Results.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/Results.tsx index 615b4e79081..87f2e91fbbb 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/Results.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/Results.tsx @@ -90,8 +90,7 @@ const Results = ({ id, rows }: { id: string; rows: readonly any[] }) => { '[&>.rdg-cell]:items-center'} onSelectedCellChange={onSelectedCellChange} /> diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx index 294b223a73a..7cd4448d153 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx @@ -136,20 +136,18 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => { /> - <> - - -

    Download CSV

    -
    - - -

    Copy as markdown

    -
    - - -

    Copy as JSON

    -
    - + + +

    Download CSV

    +
    + + +

    Copy as markdown

    +
    + + +

    Copy as JSON

    +
    ) diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityPanel.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityPanel.tsx index 9c5187afc6d..e976d4c9587 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityPanel.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityPanel.tsx @@ -1,17 +1,16 @@ -import { useMemo, useState } from 'react' -import ResultsDropdown from './ResultsDropdown' -import UtilityActions from './UtilityActions' -import UtilityTabResults from './UtilityTabResults' +import { useQueryClient } from '@tanstack/react-query' +import { useParams } from 'common' +import toast from 'react-hot-toast' + +import { useContentQuery } from 'data/content/content-query' +import { useContentUpsertMutation } from 'data/content/content-upsert-mutation' +import { contentKeys } from 'data/content/keys' import { useSqlEditorStateSnapshot } from 'state/sql-editor' import { TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_, Tabs_Shadcn_ } from 'ui' import { ChartConfig } from './ChartConfig' -import { useContentUpsertMutation } from 'data/content/content-upsert-mutation' -import { useContentQuery } from 'data/content/content-query' -import { useParams } from 'common' -import { useQueryClient } from '@tanstack/react-query' -import toast from 'react-hot-toast' -import { contentKeys } from 'data/content/keys' -import { SqlSnippets } from 'types' +import ResultsDropdown from './ResultsDropdown' +import UtilityActions from './UtilityActions' +import UtilityTabResults from './UtilityTabResults' export type UtilityPanelProps = { id: string @@ -111,7 +110,7 @@ const UtilityPanel = ({ } return ( - +
    @@ -125,7 +124,7 @@ const UtilityPanel = ({ Chart
    -
    +
    {result && result.rows && } { setIsGeneratingKey(false)} - onSelectConfirm={() => handleJwtSecretUpdate('ROLL', setIsGeneratingKey)} - > - - - - This will invalidate all existing API keys - + title="Confirm to generate a new JWT secret" + confirmLabel="Generate new secret" + confirmLabelLoading="Generating" + onCancel={() => setIsGeneratingKey(false)} + onConfirm={() => handleJwtSecretUpdate('ROLL', setIsGeneratingKey)} + alert={{ + title: 'This will invalidate all existing API keys', + description: ( + <> Generating a new JWT secret will invalidate all of your API keys, including your service_role and{' '} anon keys. Your project will also be restarted during this process, which will terminate any existing connections. You may receive API errors for up to 2 minutes while the new secret is deployed. - - -

    - This action cannot be undone and the old JWT secret will be lost. All existing API keys - will be invalidated, and any open connections will be terminated. -

    -
    + + ), + }} + > +

    + This action cannot be undone and the old JWT secret will be lost. All existing API keys + will be invalidated, and any open connections will be terminated. +

    { setShowUnban(false)} - > - -
    - - - This action cannot be undone - - Are you sure you want to unban this IP address {selectedIPToUnban}? - - -
    -
    -
    + title="Confirm Unban IP" + confirmLabel="Confirm Unban" + confirmLabelLoading="Unbanning..." + onCancel={() => setShowUnban(false)} + onConfirm={onConfirmUnbanIP} + alert={{ + title: 'This action cannot be undone', + description: `Are you sure you want to unban this IP address ${selectedIPToUnban}?`, + }} + />
    ) } diff --git a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.constants.ts b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.constants.ts index 3d7f7ea2653..6b6e15d41bb 100644 --- a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.constants.ts +++ b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.constants.ts @@ -3,27 +3,27 @@ export const POOLING_OPTIMIZATIONS = { ci_nano: { - maxClientConn: 100, - poolSize: 10, + maxClientConn: 200, + poolSize: 15, }, ci_micro: { maxClientConn: 200, poolSize: 15, }, ci_small: { - maxClientConn: 200, + maxClientConn: 400, poolSize: 15, }, ci_medium: { - maxClientConn: 200, + maxClientConn: 600, poolSize: 15, }, ci_large: { - maxClientConn: 300, - poolSize: 15, + maxClientConn: 800, + poolSize: 20, }, ci_xlarge: { - maxClientConn: 700, + maxClientConn: 1000, poolSize: 20, }, ci_2xlarge: { diff --git a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.tsx b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.tsx index 42de261126e..7d761f8a3b7 100644 --- a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.tsx +++ b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.tsx @@ -21,12 +21,12 @@ import { IconExternalLink, Input_Shadcn_, Listbox, + Separator, } from 'ui' import z from 'zod' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import AlertError from 'components/ui/AlertError' -import Divider from 'components/ui/Divider' import { FormActions } from 'components/ui/Forms' import Panel from 'components/ui/Panel' import ShimmeringLoader from 'components/ui/ShimmeringLoader' @@ -198,7 +198,7 @@ export const ConnectionPooling = () => {
    - + ))} diff --git a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx index 78e327fd269..be5335b2b54 100644 --- a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx +++ b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx @@ -7,8 +7,6 @@ import { CollapsibleContent_Shadcn_, CollapsibleTrigger_Shadcn_, Collapsible_Shadcn_, - IconChevronDown, - IconExternalLink, Input, Separator, Tabs, @@ -34,6 +32,7 @@ import { getConnectionStrings, getPoolerTld, } from './DatabaseSettings.utils' +import { ChevronDown, ExternalLink } from 'lucide-react' const CONNECTION_TYPES = [ { id: 'uri', label: 'URI' }, @@ -174,7 +173,7 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin appearance === 'minimal' && 'border-0 shadow-none' )} bodyClassName={cn(appearance === 'minimal' && 'bg-transparent')} - headerClasses={cn(appearance === 'minimal' && 'bg-transparent')} + titleClasses={cn(appearance === 'minimal' && 'bg-transparent')} title={
    {readReplicasEnabled && } -
    + } - buttonLabel="Activate" - buttonLoadingLabel="Activating" - onSelectCancel={() => setIsActivateConfirmModalVisible(false)} - onSelectConfirm={onActivateCustomDomain} + confirmLabel="Activate" + confirmLabelLoading="Activating" + onCancel={() => setIsActivateConfirmModalVisible(false)} + onConfirm={onActivateCustomDomain} > - -

    The existing Supabase subdomain will be deactivated.

    -
    +

    The existing Supabase subdomain will be deactivated.

    ) diff --git a/apps/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx b/apps/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx index 82d7d190067..53bc74a3069 100644 --- a/apps/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx +++ b/apps/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx @@ -94,22 +94,19 @@ const PauseProjectButton = () => { ) : null} setIsModalOpen(false)} - onSelectConfirm={requestPauseProject} + title="Pause this project?" + confirmLabel="Pause project" + confirmLabelLoading="Pausing project" + onCancel={() => setIsModalOpen(false)} + onConfirm={requestPauseProject} > - -

    - Are you sure you want to pause this project? It will not be accessible until you unpause - it. -

    -
    +

    + Are you sure you want to pause this project? It will not be accessible until you unpause + it. +

    ) diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx index d7b7fa7b37a..acb257b643a 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx @@ -20,6 +20,8 @@ import { useSelectedOrganization, useSelectedProject } from 'hooks' import { AWS_REGIONS, AWS_REGIONS_DEFAULT, AWS_REGIONS_KEYS, BASE_PATH } from 'lib/constants' import { AVAILABLE_REPLICA_REGIONS, AWS_REGIONS_VALUES } from './InstanceConfiguration.constants' import { useBackupsQuery } from 'data/database/backups-query' +import { useEnablePhysicalBackupsMutation } from 'data/database/enable-physical-backups-mutation' +import { ExternalLink } from 'lucide-react' // [Joshen] FYI this is purely for AWS only, need to update to support Fly eventually @@ -39,12 +41,33 @@ const DeployNewReplicaPanel = ({ const { ref: projectRef } = useParams() const project = useSelectedProject() const org = useSelectedOrganization() + const [refetchInterval, setRefetchInterval] = useState(false) const { data } = useReadReplicasQuery({ projectRef }) - const { data: backups } = useBackupsQuery({ projectRef }) + const { data: backups } = useBackupsQuery( + { projectRef }, + { + refetchInterval, + refetchOnWindowFocus: false, + onSuccess: (data) => { + if (data.walg_enabled) setRefetchInterval(false) + }, + } + ) const { data: addons, isSuccess } = useProjectAddonsQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug }) + const { mutate: enablePhysicalBackups, isLoading: isEnabling } = useEnablePhysicalBackupsMutation( + { + onSuccess: () => { + toast.success( + 'Physical backups are currently being enabled, please check back in a few minutes!' + ) + setRefetchInterval(5000) + }, + } + ) + const { mutate: setUpReplica, isLoading: isSettingUp } = useReadReplicaSetUpMutation({ onSuccess: () => { const region = AVAILABLE_REPLICA_REGIONS.find((r) => r.key === selectedRegion)?.name @@ -128,37 +151,77 @@ const DeployNewReplicaPanel = ({ - Point in time recovery is required to deploy replicas + {refetchInterval !== false + ? 'Physical backups are currently being enabled' + : 'Physical backups are required to deploy replicas'} - {isFreePlan ? ( - - To enable PITR, you may first upgrade your organization's plan to at least Pro, then - purchase the PITR add on for your project via the{' '} - - project settings - - . - - ) : ( - - Enable the add-on in your project's settings first before deploying read replicas. + {refetchInterval === false && ( + + Physical backups are used under the hood to spin up read replicas for your project. )} - - + Enable physical backups + + + + )} + + )} + + {currentComputeAddon === undefined && ( + + + + Project required to at least be on a Small compute + + + + This is to ensure that read replicas can keep up with the primary databases' + activities. + +
    + + +
    )} @@ -253,9 +316,9 @@ const DeployNewReplicaPanel = ({ href="https://supabase.com/docs/guides/platform/org-based-billing#usage-based-billing-for-compute" target="_blank" rel="noreferrer" - className="underline" + className="underline hover:text-foreground transition" > - Usage-based billing + usage-based billing {' '} for compute.

    diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx index 76e71c4117d..f3b973fc212 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx @@ -59,31 +59,24 @@ const DropAllReplicasConfirmationModal = ({ return ( onCancel()} - onSelectConfirm={() => onConfirmRemove()} + title="Confirm to drop all read replicas?" + confirmLabel="Drop all replicas" + confirmLabelLoading="Dropping all replicas" + onCancel={() => onCancel()} + onConfirm={() => onConfirmRemove()} + alert={{ + title: 'This action cannot be undone', + description: 'You may still deploy new replicas in this region thereafter', + }} > - - - - This action cannot be undone - - You may still deploy new replicas in this region thereafter - - -
    -

    Before deleting all replicas, consider:

    -
      -
    • Network traffic from this region may slow down
    • -
    -
    -
    +

    Before deleting all replicas, consider:

    +
      +
    • Network traffic from this region may slow down
    • +
    ) } diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx index 50ea8ea2e21..096b5196991 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx @@ -43,34 +43,27 @@ const DropReplicaConfirmationModal = ({ return ( onCancel()} - onSelectConfirm={() => onConfirmRemove()} + title={`Confirm to drop selected replica? (ID: ${formattedId})`} + confirmLabel="Drop replica" + confirmLabelLoading="Dropping replica" + onCancel={() => onCancel()} + onConfirm={() => onConfirmRemove()} + alert={{ + title: 'This action cannot be undone', + description: 'You may still deploy a new replica in this region thereafter', + }} > - - - - This action cannot be undone - - You may still deploy a new replica in this region thereafter - - -
    -

    Before deleting this replica, consider:

    -
      -
    • - Network traffic from this region may slow down, especially if you have no other - replicas in this region -
    • -
    -
    -
    +

    Before deleting this replica, consider:

    +
      +
    • + Network traffic from this region may slow down, especially if you have no other replicas + in this region +
    • +
    ) } diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx index cbe5fb1cf77..3d9d7be27be 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx @@ -285,24 +285,22 @@ const InstanceConfigurationUI = () => { {/* setSelectedReplicaToRestart(undefined)} - onSelectConfirm={() => onConfirmRestartReplica()} + title="Confirm to restart selected replica?" + confirmLabel="Restart replica" + confirmLabelLoading="Restarting replica" + onCancel={() => setSelectedReplicaToRestart(undefined)} + onConfirm={() => onConfirmRestartReplica()} > - -

    Before restarting the replica, consider:

    -
      -
    • - Network traffic from this region may slow down while the replica is restarting, - especially if you have no other replicas in this region -
    • -
    -

    - Are you sure you want to restart this replica (ID: {selectedReplicaToRestart?.id}) now?{' '} -

    -
    +

    Before restarting the replica, consider:

    +
      +
    • + Network traffic from this region may slow down while the replica is restarting, + especially if you have no other replicas in this region +
    • +
    +

    + Are you sure you want to restart this replica (ID: {selectedReplicaToRestart?.id}) now?{' '} +

    */} ) diff --git a/apps/studio/components/interfaces/Settings/Logs/Logs.SavedQueriesItem.tsx b/apps/studio/components/interfaces/Settings/Logs/Logs.SavedQueriesItem.tsx index 0b4fa8195c0..c72039b9996 100644 --- a/apps/studio/components/interfaces/Settings/Logs/Logs.SavedQueriesItem.tsx +++ b/apps/studio/components/interfaces/Settings/Logs/Logs.SavedQueriesItem.tsx @@ -132,20 +132,18 @@ const SavedQueriesItem = ({ item }: SavedQueriesItemProps) => { { + confirmLabel="Delete query" + title="Confirm to delete saved query" + onCancel={() => { setShowConfirmModal(false) }} - onSelectConfirm={onConfirmDelete} + onConfirm={onConfirmDelete} > - -

    - Are you sure you want to delete {item.name}? -

    -
    +

    + Are you sure you want to delete {item.name}? +

    { - {idx !== keys.length - 1 && } + {idx !== keys.length - 1 && } ) })} diff --git a/apps/studio/components/interfaces/Settings/Vault/Secrets/SecretsManagement.tsx b/apps/studio/components/interfaces/Settings/Vault/Secrets/SecretsManagement.tsx index 99ffbf7048f..886528736a3 100644 --- a/apps/studio/components/interfaces/Settings/Vault/Secrets/SecretsManagement.tsx +++ b/apps/studio/components/interfaces/Settings/Vault/Secrets/SecretsManagement.tsx @@ -6,11 +6,19 @@ import { Fragment, useEffect, useState } from 'react' import { useParams } from 'common' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import Divider from 'components/ui/Divider' import { useVaultSecretsQuery } from 'data/vault/vault-secrets-query' import { useCheckPermissions } from 'hooks' import type { VaultSecret } from 'types' -import { Button, IconExternalLink, IconLoader, IconSearch, IconX, Input, Listbox } from 'ui' +import { + Button, + IconExternalLink, + IconLoader, + IconSearch, + IconX, + Input, + Listbox, + Separator, +} from 'ui' import AddNewSecretModal from './AddNewSecretModal' import DeleteSecretModal from './DeleteSecretModal' import EditSecretModal from './EditSecretModal' @@ -172,7 +180,7 @@ const SecretsManagement = () => { onSelectEdit={setSelectedSecretToEdit} onSelectRemove={setSelectedSecretToRemove} /> - {idx !== secrets.length - 1 && } + {idx !== secrets.length - 1 && } ) })} diff --git a/apps/studio/components/interfaces/SignIn/SignInMfaForm.tsx b/apps/studio/components/interfaces/SignIn/SignInMfaForm.tsx index 3dd480112ef..b50a163975f 100644 --- a/apps/studio/components/interfaces/SignIn/SignInMfaForm.tsx +++ b/apps/studio/components/interfaces/SignIn/SignInMfaForm.tsx @@ -1,4 +1,4 @@ -import type { AuthError } from '@supabase/gotrue-js' +import type { AuthError } from '@supabase/auth-js' import type { Factor } from '@supabase/supabase-js' import { useQueryClient } from '@tanstack/react-query' import Link from 'next/link' diff --git a/apps/studio/components/interfaces/Support/Success.tsx b/apps/studio/components/interfaces/Support/Success.tsx index a654305183e..b58b409c17f 100644 --- a/apps/studio/components/interfaces/Support/Success.tsx +++ b/apps/studio/components/interfaces/Support/Success.tsx @@ -1,8 +1,7 @@ import Link from 'next/link' import { useState } from 'react' -import { Button, IconCheck, IconExternalLink, IconMail, IconSearch, Input } from 'ui' +import { Button, IconCheck, IconExternalLink, IconMail, IconSearch, Input, Separator } from 'ui' -import Divider from 'components/ui/Divider' import { CATEGORY_OPTIONS } from './Support.constants' import { useProfile } from 'lib/profile' @@ -36,7 +35,7 @@ const Success = ({ sentCategory = '' }: SuccessProps) => { {categoriesToShowAdditionalResources.includes(sentCategory) && ( <>
    - +

    In the meantime, tap into our community

    @@ -72,7 +71,7 @@ const Success = ({ sentCategory = '' }: SuccessProps) => { )}
    - +
    diff --git a/apps/studio/components/interfaces/Support/SupportForm.tsx b/apps/studio/components/interfaces/Support/SupportForm.tsx index 11eb7c4e590..d2abdeff670 100644 --- a/apps/studio/components/interfaces/Support/SupportForm.tsx +++ b/apps/studio/components/interfaces/Support/SupportForm.tsx @@ -6,7 +6,6 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react' import toast from 'react-hot-toast' import { useParams } from 'common' -import Divider from 'components/ui/Divider' import InformationBox from 'components/ui/InformationBox' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { getProjectAuthConfig } from 'data/auth/auth-config-query' @@ -34,6 +33,7 @@ import { IconX, Input, Listbox, + Separator, } from 'ui' import MultiSelect from 'ui-patterns/MultiSelect' import DisabledStateForFreeTier from './DisabledStateForFreeTier' @@ -532,7 +532,7 @@ const SupportForm = ({ setSentCategory }: SupportFormProps) => {
    )} - + {!isDisabled ? ( <> diff --git a/apps/studio/components/interfaces/TableGridEditor/DeleteConfirmationDialogs.tsx b/apps/studio/components/interfaces/TableGridEditor/DeleteConfirmationDialogs.tsx index fcd9ba50561..a76fd8a4bf6 100644 --- a/apps/studio/components/interfaces/TableGridEditor/DeleteConfirmationDialogs.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/DeleteConfirmationDialogs.tsx @@ -1,6 +1,15 @@ import Link from 'next/link' import toast from 'react-hot-toast' -import { Alert, Button, Checkbox, IconExternalLink, Modal } from 'ui' +import { + Alert, + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, + Button, + Checkbox, + IconExternalLink, + Modal, +} from 'ui' import type { SupaRow } from 'components/grid' import { formatFilterURLParams } from 'components/grid/SupabaseGrid.utils' @@ -220,40 +229,39 @@ const DeleteConfirmationDialogs = ({ return ( <> { + confirmLabel="Delete" + confirmLabelLoading="Deleting" + onCancel={() => { snap.closeConfirmationDialog() }} - onSelectConfirm={onConfirmDeleteColumn} + onConfirm={onConfirmDeleteColumn} > - -
    -

    - Are you sure you want to delete the selected column? This action cannot be undone. -

    - snap.toggleConfirmationIsWithCascade()} - /> - {isDeleteWithCascade && ( - -

    - All dependent objects will be removed, as will any objects that depend on them, - recursively. -

    +
    +

    + Are you sure you want to delete the selected column? This action cannot be undone. +

    + snap.toggleConfirmationIsWithCascade()} + /> + {isDeleteWithCascade && ( + + + All dependent objects will be removed, as will any objects that depend on them, + recursively. + + - - )} -
    - + + + )} +
    {`Confirm deletion of table "${selectedTable?.name}"`} } - buttonLabel="Delete" - buttonLoadingLabel="Deleting" - onSelectCancel={() => { + confirmLabel="Delete" + confirmLabelLoading="Deleting" + onCancel={() => { snap.closeConfirmationDialog() }} - onSelectConfirm={onConfirmDeleteTable} + onConfirm={onConfirmDeleteTable} > - -
    -

    - Are you sure you want to delete the selected table? This action cannot be undone. -

    - snap.toggleConfirmationIsWithCascade(!isDeleteWithCascade)} - /> - {isDeleteWithCascade && ( - -

    - All dependent objects will be removed, as will any objects that depend on them, - recursively. -

    - -
    - )} -
    -
    +
    +

    + Are you sure you want to delete the selected table? This action cannot be undone. +

    + snap.toggleConfirmationIsWithCascade(!isDeleteWithCascade)} + /> + {isDeleteWithCascade && ( + +

    + All dependent objects will be removed, as will any objects that depend on them, + recursively. +

    + +
    + )} +
    Confirm to delete the selected row{numRows > 1 && 's'} } - buttonLabel="Delete" - buttonLoadingLabel="Deleting" - onSelectCancel={() => snap.closeConfirmationDialog()} - onSelectConfirm={() => onConfirmDeleteRow()} + confirmLabel="Delete" + confirmLabelLoading="Deleting" + onCancel={() => snap.closeConfirmationDialog()} + onConfirm={() => onConfirmDeleteRow()} > - -
    -

    - Are you sure you want to delete {isAllRowsSelected ? 'all' : 'the selected'}{' '} - {numRows > 1 && `${numRows} `}row - {numRows > 1 && 's'}? This action cannot be undone. -

    -
    -
    +
    +

    + Are you sure you want to delete {isAllRowsSelected ? 'all' : 'the selected'}{' '} + {numRows > 1 && `${numRows} `}row + {numRows > 1 && 's'}? This action cannot be undone. +

    +
    ) diff --git a/apps/studio/components/interfaces/TableGridEditor/GridHeaderActions.tsx b/apps/studio/components/interfaces/TableGridEditor/GridHeaderActions.tsx index 363bd9a890e..0bd784d291c 100644 --- a/apps/studio/components/interfaces/TableGridEditor/GridHeaderActions.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/GridHeaderActions.tsx @@ -267,13 +267,13 @@ const GridHeaderActions = ({ table, isViewSelected, isTableSelected }: GridHeade setShowEnableRealtime(false)} - onSelectConfirm={() => toggleRealtime()} + title={`${isRealtimeEnabled ? 'Disable' : 'Enable'} realtime for ${table.name}`} + confirmLabel={`${isRealtimeEnabled ? 'Disable' : 'Enable'} realtime`} + confirmLabelLoading={`${isRealtimeEnabled ? 'Disabling' : 'Enabling'} realtime`} + onCancel={() => setShowEnableRealtime(false)} + onConfirm={() => toggleRealtime()} > - +

    Once realtime has been {isRealtimeEnabled ? 'disabled' : 'enabled'}, the table will{' '} {isRealtimeEnabled ? 'no longer ' : ''}broadcast any changes to authorized subscribers. @@ -287,7 +287,7 @@ const GridHeaderActions = ({ table, isViewSelected, isTableSelected }: GridHeade settings.

    )} - +
    { } return ( -
    +
    { resetBreadcrumbs={resetBreadcrumbs} />
    -
    +
    diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx index 0fc87addb3e..5e0c20ea30b 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx @@ -53,7 +53,7 @@ export const TextEditor = ({
    diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx index bbac0394d9f..97cb7db0674 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx @@ -642,21 +642,19 @@ const SidePanelEditor = ({ /> setIsClosingPanel(false)} - onSelectConfirm={() => { + title="Discard changes" + confirmLabel="Discard" + onCancel={() => setIsClosingPanel(false)} + onConfirm={() => { setIsClosingPanel(false) setIsEdited(false) snap.closeSidePanel() }} > - -

    - There are unsaved changes. Are you sure you want to close the panel? Your changes will - be lost. -

    -
    +

    + There are unsaved changes. Are you sure you want to close the panel? Your changes will be + lost. +

    ) diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx index aac92fe2d89..fb40e8e7a05 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx @@ -402,18 +402,16 @@ const TableEditor = ({ setRlsConfirmVisible(false)} - onSelectConfirm={() => { + onCancel={() => setRlsConfirmVisible(false)} + onConfirm={() => { onUpdateField({ isRLSEnabled: !tableFields.isRLSEnabled }) setRlsConfirmVisible(false) }} > - - - + diff --git a/apps/studio/components/layouts/APIAuthorizationLayout.tsx b/apps/studio/components/layouts/APIAuthorizationLayout.tsx index 960dd6f8f83..e4342ed1d50 100644 --- a/apps/studio/components/layouts/APIAuthorizationLayout.tsx +++ b/apps/studio/components/layouts/APIAuthorizationLayout.tsx @@ -1,9 +1,9 @@ -import Divider from 'components/ui/Divider' import { BASE_PATH } from 'lib/constants' import { useTheme } from 'next-themes' import Head from 'next/head' import Image from 'next/legacy/image' import type { PropsWithChildren } from 'react' +import { Separator } from 'ui' export interface APIAuthorizationLayoutProps {} @@ -36,7 +36,7 @@ const APIAuthorizationLayout = ({ children }: PropsWithChildren
    - +
    {children}
    diff --git a/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx b/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx index 9b661f3c384..d2fd5030540 100644 --- a/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx +++ b/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx @@ -1,5 +1,5 @@ +import { ExternalLink } from 'lucide-react' import Link from 'next/link' -import { IconExternalLink } from 'ui' const IncidentBanner = () => { return ( @@ -8,7 +8,7 @@ const IncidentBanner = () => {

    We are currently investigating a technical issue, follow status.supabase.com for updates

    - +
    ) diff --git a/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx b/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx index 679a75318a5..ca5b12fe04f 100644 --- a/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx +++ b/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx @@ -1,11 +1,12 @@ import { useSupabaseClient } from '@supabase/auth-helpers-react' import { useQuery } from '@tanstack/react-query' +import { ExternalLink } from 'lucide-react' import { useRouter } from 'next/router' -import { useParams } from 'common' +import { useParams } from 'common' import { useAppBannerContext } from 'components/interfaces/App/AppBannerWrapperContext' import { useProfile } from 'lib/profile' -import { Button, IconExternalLink } from 'ui' +import { Button } from 'ui' // [Joshen] For this notice specifically, just FYI // 1 month after 26th Jan we'll need to add some contextual information about this deprecation @@ -96,7 +97,7 @@ export const NoticeBanner = () => { 'We are migrating our infrastructure from IPv4 to IPv6. Please migrate now. You can ignore this warning if you have already migrated.'}

    - + + + ) +} diff --git a/apps/studio/components/layouts/DatabaseLayout/DatabaseMenu.utils.ts b/apps/studio/components/layouts/DatabaseLayout/DatabaseMenu.utils.ts index 4f6f6f81c07..26af4befb0d 100644 --- a/apps/studio/components/layouts/DatabaseLayout/DatabaseMenu.utils.ts +++ b/apps/studio/components/layouts/DatabaseLayout/DatabaseMenu.utils.ts @@ -91,6 +91,18 @@ export const generateDatabaseMenu = ( url: `/project/${ref}/database/types`, items: [], }, + { + name: 'Query Performance', + key: 'query-performance', + url: `/project/${ref}/database/query-performance`, + items: [], + }, + { + name: 'Database Linter', + key: 'linter', + url: `/project/${ref}/database/linter`, + items: [], + }, ], }, ] diff --git a/apps/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx b/apps/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx index 53e287a291a..9f272918926 100644 --- a/apps/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx +++ b/apps/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx @@ -1,4 +1,5 @@ import { PropsWithChildren } from 'react' +import InlineSVG from 'react-inlinesvg' import { useParams } from 'common' import { BASE_PATH } from 'lib/constants' @@ -6,8 +7,8 @@ import IntegrationWindowLayout from './IntegrationWindowLayout' import { useIntegrationInstallationSnapshot } from 'state/integration-installation' const VERCEL_ICON = ( -
    - Vercel Icon +
    +
    ) diff --git a/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx b/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx index 4d84ce59141..20b411c3395 100644 --- a/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx +++ b/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx @@ -1,41 +1,40 @@ +import { ChevronDown, Edit2, Plus, Trash } from 'lucide-react' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React from 'react' +import toast from 'react-hot-toast' + import { CreateReportModal } from 'components/interfaces/Reports/Reports.CreateReportModal' import { UpdateCustomReportModal } from 'components/interfaces/Reports/Reports.UpdateModal' -import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useContentDeleteMutation } from 'data/content/content-delete-mutation' import { useContentInsertMutation } from 'data/content/content-insert-mutation' import { Content, useContentQuery } from 'data/content/content-query' import { useContentUpsertMutation } from 'data/content/content-upsert-mutation' import { useIsFeatureEnabled, useSelectedProject } from 'hooks' -import { uuidv4 } from 'lib/helpers' -import Link from 'next/link' -import { useRouter } from 'next/router' -import React from 'react' -import toast from 'react-hot-toast' import { + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, - IconChevronDown, - IconEdit2, - IconPlus, - IconTrash, Menu, - Modal, cn, } from 'ui' +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' const ReportsMenu = () => { const router = useRouter() - const insertReport = useContentInsertMutation() + const { id } = router.query + const project = useSelectedProject() const deleteReport = useContentDeleteMutation() const updateReport = useContentUpsertMutation() + const storageEnabled = useIsFeatureEnabled('project_storage:all') - const project = useSelectedProject() - const { id } = router.query const pageKey = (id || router.pathname.split('/')[4]) as string const ref = project?.ref ?? 'default' @@ -44,8 +43,6 @@ const ReportsMenu = () => { const [showUpdateReportModal, setShowUpdateReportModal] = React.useState(false) const [selectedReport, setSelectedReport] = React.useState() - const storageEnabled = useIsFeatureEnabled('project_storage:all') - const { data: content, isLoading } = useContentQuery(ref) function getReportMenuItems() { @@ -103,53 +100,10 @@ const ReportsMenu = () => { key: 'database', url: `/project/${ref}/reports/database`, }, - { - name: 'Query Performance', - key: 'query-performance', - url: `/project/${ref}/reports/query-performance`, - }, ], }, ] - async function createCustomReport({ name, description }: { name: string; description?: string }) { - try { - if (!ref) return - - const res = await insertReport.mutateAsync({ - projectRef: ref, - payload: { - id: uuidv4(), - type: 'report', - name, - description: description || '', - visibility: 'project', - content: { - schema_version: 1, - period_start: { - time_period: '7d', - date: '', - }, - period_end: { - time_period: 'today', - date: '', - }, - interval: '1d', - layout: [], - }, - }, - }) - toast.success('New report created') - - const newReportId = res[0].id - setShowNewReportModal(false) - router.push(`/project/${ref}/reports/${newReportId}`) - } catch (error) { - toast.error(`Failed to create report. Check console for more details.`) - console.error(error) - } - } - return ( {isLoading ? ( @@ -159,7 +113,7 @@ const ReportsMenu = () => {
    ) : ( -
    +
    + {reportMenuItems.length > 0 ? ( -
    +
    {reportMenuItems.map((item, idx) => ( {
    ) : null} - {menuItems.map((item, idx) => ( -
    + + {menuItems.map((item) => ( +
    {item.items ? ( <> @@ -250,6 +206,22 @@ const ReportsMenu = () => { ) : null}
    ))} + + {/* [Joshen] Temp notice while we shift some pages on 040424 - can probably remove in 3 months perhaps */} + + + Query Performance and Project Linter reports have been shifted + + +

    They can now be found in the menu under the database section.

    + +
    +
    + { try { @@ -281,14 +253,16 @@ const ReportsMenu = () => { description: selectedReport?.description || '', }} /> + { + onCancel={() => setDeleteModalOpen(false)} + onConfirm={async () => { if (selectedReport) { if (!selectedReport.id) return await deleteReport.mutateAsync({ @@ -300,18 +274,14 @@ const ReportsMenu = () => { } setDeleteModalOpen(false) }} - onSelectCancel={() => setDeleteModalOpen(false)} > - -
    -
    -
    -

    Are you sure you want to delete '{selectedReport?.name}'?

    -
    -
    +
    +
    +

    Are you sure you want to delete '{selectedReport?.name}'?

    - +
    + { diff --git a/apps/studio/components/layouts/SQLEditorLayout/QueryItem.tsx b/apps/studio/components/layouts/SQLEditorLayout/QueryItem.tsx index d260d20d1a5..d7f0bc473f8 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/QueryItem.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/QueryItem.tsx @@ -28,6 +28,7 @@ import type { SqlSnippet } from 'data/content/sql-snippets-query' import { useSqlEditorStateSnapshot } from 'state/sql-editor' import { CriticalIcon, WarningIcon } from 'ui-patterns/Icons/StatusIcons' import { QueryItemActions } from './QueryItemActions' +import { Eye, Unlock } from 'lucide-react' export interface QueryItemProps { tabInfo: SqlSnippet @@ -188,58 +189,50 @@ const QueryItem = ({ onComplete={() => setRenameModalOpen(false)} /> setDeleteModalOpen(false)} + variant={'destructive'} + onCancel={() => setDeleteModalOpen(false)} + onConfirm={onConfirmDelete} + alert={ + visibility === 'project' + ? { + title: 'This SQL snippet will be lost forever', + description: + 'Deleting this query will remove it for all members of the project team.', + } + : {} + } > - - {visibility === 'project' && ( - - - This SQL snippet will be lost forever - - Deleting this query will remove it for all members of the project team. - - - )} -

    Are you sure you want to delete '{name}'?

    -
    +

    Are you sure you want to delete '{name}'?

    setShareModalOpen(false)} + onCancel={() => setShareModalOpen(false)} + onConfirm={onConfirmShare} + alert={{ + title: 'This SQL query will become public to all team members', + description: 'Anyone with access to the project can view it', + }} > - - - - - This SQL query will become public to all team members - - - Anyone with access to the project can view it - - -
      -
    • - - Project members will have read-only access to this query. -
    • -
    • - - Anyone will be able to duplicate it to their personal snippets. -
    • -
    -
    +
      +
    • + + Project members will have read-only access to this query. +
    • +
    • + + Anyone will be able to duplicate it to their personal snippets. +
    • +
    {
    1 ? 'ies' : 'y'}`} - buttonLoadingLabel="Deleting query" + title="Confirm to delete query" + confirmLabel={`Delete ${selectedQueries.length.toLocaleString()} quer${selectedQueries.length > 1 ? 'ies' : 'y'}`} + confirmLabelLoading="Deleting query" size="medium" loading={isDeleting} visible={showDeleteModal} - onSelectConfirm={onConfirmDelete} - onSelectCancel={() => setShowDeleteModal(false)} - danger + onConfirm={onConfirmDelete} + onCancel={() => setShowDeleteModal(false)} + variant={'destructive'} + alert={{ + title: 'This action cannot be undone', + description: 'The selected SQL snippets cannot be recovered once deleted', + }} > - -
    -
    -
    - - - This action cannot be undone - - The selected SQL snippets cannot be recovered once deleted - - -

    - Are you sure you want to delete the selected {selectedQueries.length} quer - {selectedQueries.length > 1 ? 'ies' : 'y'}? -

    -
    -
    -
    -
    +

    + Are you sure you want to delete the selected {selectedQueries.length} quer + {selectedQueries.length > 1 ? 'ies' : 'y'}? +

    ) diff --git a/apps/studio/components/layouts/Scaffold.tsx b/apps/studio/components/layouts/Scaffold.tsx index 71d3ea68279..f9f13485c62 100644 --- a/apps/studio/components/layouts/Scaffold.tsx +++ b/apps/studio/components/layouts/Scaffold.tsx @@ -3,11 +3,8 @@ import { cn } from 'ui' const maxWidthClasses = 'mx-auto w-full max-w-[1600px]' const paddingClasses = 'px-6 lg:px-14 xl:px-28 2xl:px-32' - const maxWidthClassesColumn = 'min-w-[420px]' -// lg: pt - 8 - const ScaffoldHeader = React.forwardRef>( ({ className, ...props }, ref) => { return ( @@ -31,7 +28,7 @@ const ScaffoldContainer = React.forwardRef>( ({ className, ...props }, ref) => { - return
    + return
    } ) diff --git a/apps/studio/components/layouts/VercelIntegrationLayout.tsx b/apps/studio/components/layouts/VercelIntegrationLayout.tsx index 34bf4f2983a..cd57fb5bbb1 100644 --- a/apps/studio/components/layouts/VercelIntegrationLayout.tsx +++ b/apps/studio/components/layouts/VercelIntegrationLayout.tsx @@ -1,8 +1,8 @@ import Head from 'next/head' import type { PropsWithChildren } from 'react' -import Divider from 'components/ui/Divider' import { BASE_PATH } from 'lib/constants' +import { Separator } from 'ui' const VercelIntegrationLayout = ({ children }: PropsWithChildren<{}>) => { return ( @@ -27,7 +27,7 @@ const VercelIntegrationLayout = ({ children }: PropsWithChildren<{}>) => {
    - +
    {children}
    diff --git a/apps/studio/components/to-be-cleaned/Charts/ChartHandler.types.ts b/apps/studio/components/to-be-cleaned/Charts/ChartHandler.types.ts index 9cfdbbf1429..e6b0f65b178 100644 --- a/apps/studio/components/to-be-cleaned/Charts/ChartHandler.types.ts +++ b/apps/studio/components/to-be-cleaned/Charts/ChartHandler.types.ts @@ -3,7 +3,6 @@ export interface ChartData { yAxisLimit?: number maximum?: number total: number - totalAverage: number totalGrouped: Attribute data: DataPoint[] } diff --git a/apps/studio/components/to-be-cleaned/Charts/ChartRenderer.tsx b/apps/studio/components/to-be-cleaned/Charts/ChartRenderer.tsx index ff6e0ee43da..cfd484c30d3 100644 --- a/apps/studio/components/to-be-cleaned/Charts/ChartRenderer.tsx +++ b/apps/studio/components/to-be-cleaned/Charts/ChartRenderer.tsx @@ -46,17 +46,19 @@ const Header = ({ let title = '' + const isByteAttribute = + format === 'bytes' || + attribute.includes('ingress') || + attribute.includes('egress') || + attribute.includes('bytes') + if (focus) { if (!data) { title = '' } else if (format === '%') { title = Number(data[focus]?.[attribute]).toFixed(2) } else { - if ( - attribute.includes('ingress') || - attribute.includes('egress') || - attribute.includes('bytes') - ) { + if (isByteAttribute) { title = formatBytes(data[focus]?.[attribute]) } else { title = data[focus]?.[attribute]?.toLocaleString() @@ -66,11 +68,7 @@ const Header = ({ if (format === '%' && highlightedValue) { title = highlightedValue.toFixed(2) } else { - if ( - attribute.includes('ingress') || - attribute.includes('egress') || - attribute.includes('bytes') - ) { + if (isByteAttribute) { title = formatBytes(highlightedValue) } else { title = highlightedValue?.toLocaleString() @@ -91,7 +89,7 @@ const Header = ({ } > {title} - {format} + {!isByteAttribute && {format}} ) const date = ( diff --git a/apps/studio/components/to-be-cleaned/Storage/EmptyBucketModal.tsx b/apps/studio/components/to-be-cleaned/Storage/EmptyBucketModal.tsx index c8ec9060e0c..4ea1860f3fe 100644 --- a/apps/studio/components/to-be-cleaned/Storage/EmptyBucketModal.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/EmptyBucketModal.tsx @@ -40,24 +40,19 @@ export const EmptyBucketModal = ({ visible = false, bucket, onClose }: EmptyBuck return ( onClose()} - onSelectConfirm={onEmptyBucket} - header={`Confirm to delete all contents from ${bucket?.name}`} - buttonLabel="Empty bucket" + onCancel={() => onClose()} + onConfirm={onEmptyBucket} + alert={{ + title: 'This action cannot be undone', + description: 'The contents of your bucket cannot be recovered once deleted', + }} > - - - - This action cannot be undone - - The contents of your bucket cannot be recovered once deleted - - -

    Are you sure you want to empty the bucket "{bucket?.name}"?

    -
    +

    Are you sure you want to empty the bucket "{bucket?.name}"?

    ) } diff --git a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.tsx b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.tsx index 19a316628d6..8ac8f205a55 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.tsx @@ -38,7 +38,7 @@ const DragOverOverlay = ({ isOpen, onDragLeave, onDrop, folderIsEmpty }: any) => > {!folderIsEmpty && (
    diff --git a/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx b/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx index e2aa4a00942..c8b4955b263 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx @@ -209,7 +209,7 @@ const StoragePolicies = () => { ) })} -
    +

    You may also write policies for the tables under the storage schema directly for greater control diff --git a/apps/studio/components/ui/Divider.tsx b/apps/studio/components/ui/Divider.tsx deleted file mode 100644 index 50ad397a0cc..00000000000 --- a/apps/studio/components/ui/Divider.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Divider({ light }: { light: Boolean }) { - return

    -} diff --git a/apps/studio/components/interfaces/AuditLogs/FilterPopover.tsx b/apps/studio/components/ui/FilterPopover.tsx similarity index 70% rename from apps/studio/components/interfaces/AuditLogs/FilterPopover.tsx rename to apps/studio/components/ui/FilterPopover.tsx index b0da2dd4967..54a60936aa2 100644 --- a/apps/studio/components/interfaces/AuditLogs/FilterPopover.tsx +++ b/apps/studio/components/ui/FilterPopover.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { Button, Checkbox, Popover } from 'ui' +import { Button, Checkbox, Popover, ScrollArea } from 'ui' interface FilterPopoverProps { options: any[] @@ -13,7 +13,7 @@ interface FilterPopoverProps { // [Joshen] Form + Checkbox.Group doesn't seem to work properly RE form state // hence why the manual implementation here as a workaround -const FilterPopover = ({ +export const FilterPopover = ({ options = [], activeOptions = [], valueKey, @@ -39,24 +39,26 @@ const FilterPopover = ({ overlay={ <>
    - { - const value = event.target.value - if (selectedOptions.includes(value)) { - setSelectedOptions(selectedOptions.filter((x) => x !== value)) - } else { - setSelectedOptions(selectedOptions.concat(value)) - } - }} - options={options.map((option) => { - return { - value: option[valueKey], - label: option[labelKey], - defaultChecked: activeOptions.includes(option[valueKey]), - } - })} - > + 7 ? 'h-[205px]' : ''}> + { + const value = event.target.value + if (selectedOptions.includes(value)) { + setSelectedOptions(selectedOptions.filter((x) => x !== value)) + } else { + setSelectedOptions(selectedOptions.concat(value)) + } + }} + options={options.map((option) => { + return { + value: option[valueKey], + label: option[labelKey], + defaultChecked: activeOptions.includes(option[valueKey]), + } + })} + /> +
    {docsUrl !== undefined && ( - +
    + +
    diff --git a/apps/studio/pages/project/[ref]/database/linter.tsx b/apps/studio/pages/project/[ref]/database/linter.tsx new file mode 100644 index 00000000000..31f48daa024 --- /dev/null +++ b/apps/studio/pages/project/[ref]/database/linter.tsx @@ -0,0 +1,230 @@ +import { partition, sortBy } from 'lodash' +import { Check, ExternalLink, Loader } from 'lucide-react' +import { useMemo, useState } from 'react' + +import { AccordionTrigger } from '@ui/components/shadcn/ui/accordion' +import ReportLintsTableRow from 'components/interfaces/Reports/ReportLintsTableRow' +import { DatabaseLayout } from 'components/layouts' +import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import Table from 'components/to-be-cleaned/Table' +import { FormHeader } from 'components/ui/Forms' +import { useProjectLintsQuery } from 'data/lint/lint-query' +import { useLocalStorageQuery, useSelectedProject } from 'hooks' +import { LOCAL_STORAGE_KEYS } from 'lib/constants' +import type { NextPageWithLayout } from 'types' +import { + AccordionContent_Shadcn_, + AccordionItem_Shadcn_, + Accordion_Shadcn_, + Button, + LoadingLine, +} from 'ui' +import { FilterPopover } from 'components/ui/FilterPopover' + +const ProjectLints: NextPageWithLayout = () => { + const project = useSelectedProject() + const [filters, setFilters] = useState({ + levels: [] as string[], + types: [] as string[], + }) + const [lintIgnoreList] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.PROJECT_LINT_IGNORE_LIST, + [] + ) + + const { data, isLoading, isRefetching, refetch } = useProjectLintsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + }) + + // sort the lints by level, ERROR should be at the top. + const lints = sortBy(data || [], (lint) => { + if (lint.level === 'ERROR') return 0 + if (lint.level === 'WARN') return 1 + if (lint.level === 'INFO') return 2 + return 3 + }) + + const [ignoredLints, activeLints] = partition(lints, (lint) => + lintIgnoreList.includes(lint.cache_key) + ) + const filteredLints = useMemo(() => { + return activeLints + .filter((x) => (filters.levels.length > 0 ? filters.levels.includes(x.level) : x)) + .filter((x) => (filters.types.length > 0 ? filters.types.includes(x.name) : x)) + }, [activeLints, filters.levels, filters.types]) + + const warnLintsCount = activeLints.filter((x) => x.level === 'WARN').length + const errorLintsCount = activeLints.filter((x) => x.level === 'ERROR').length + + return ( + + +
    + +
    + +
    +
    +
    +

    Filter by

    + setFilters({ ...filters, levels: values })} + /> + setFilters({ ...filters, types: values })} + /> +
    +

    + Identified {activeLints.length} problems{' '} + {warnLintsCount > 0 || errorLintsCount > 0 + ? `(${errorLintsCount > 0 ? `${errorLintsCount} errors` : ''}${errorLintsCount > 0 && warnLintsCount > 0 ? ', ' : ''}${warnLintsCount > 0 ? `${warnLintsCount} warnings` : ''})` + : null} +

    +
    +
    + + +
    +
    + +
    +
    + +
    + Level + , + + Problem + , + , + ]} + body={[ + + + + + , + ...(activeLints.length === 0 + ? [ + + + {isLoading ? ( +
    + +

    Checking database for issues...

    +
    + ) : ( +
    + +

    + No issues have been found for this database +

    +
    + )} +
    +
    , + ] + : (filters.levels.length > 0 || filters.types.length > 0) && + filteredLints.length === 0 + ? [ + + +

    + No problems found based on the selected filters +

    +
    +
    , + ] + : filteredLints.map((lint) => { + return + })), + ]} + /> + + + {ignoredLints.length > 0 && ( +
    + + + +
    + Ignored problems ({ignoredLints.length}) +
    +
    + +
    + +

    + {isLoading ? ( + <> + + Checking for database issues + + ) : ( + 'No issues have been found for this database' + )} +

    +
    + + ) : ( + <> + {ignoredLints.map((lint) => { + return + })} + + ) + } + /> + + + + + )} + + + ) +} + +ProjectLints.getLayout = (page) => {page} + +export default ProjectLints diff --git a/apps/studio/pages/project/[ref]/database/migrations.tsx b/apps/studio/pages/project/[ref]/database/migrations.tsx index 9e8f9061dae..24a71088400 100644 --- a/apps/studio/pages/project/[ref]/database/migrations.tsx +++ b/apps/studio/pages/project/[ref]/database/migrations.tsx @@ -1,13 +1,41 @@ +import { ExternalLink } from 'lucide-react' + import Migrations from 'components/interfaces/Database/Migrations/Migrations' import { DatabaseLayout } from 'components/layouts' -import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import { + ScaffoldContainer, + ScaffoldSection, + ScaffoldSectionContent, + ScaffoldSectionDetail, +} from 'components/layouts/Scaffold' import type { NextPageWithLayout } from 'types' +import { Button } from 'ui' +import { FormHeader } from 'components/ui/Forms' const MigrationsPage: NextPageWithLayout = () => { return ( -
    + + + + + + +
    diff --git a/apps/studio/pages/project/[ref]/database/query-performance.tsx b/apps/studio/pages/project/[ref]/database/query-performance.tsx new file mode 100644 index 00000000000..25b02b9f92c --- /dev/null +++ b/apps/studio/pages/project/[ref]/database/query-performance.tsx @@ -0,0 +1,76 @@ +import { useRouter } from 'next/router' + +import { useParams } from 'common' +import { IndexEfficiencyNotice } from 'components/interfaces/QueryPerformance/IndexEfficiencyNotice' +import { QueryPerformance } from 'components/interfaces/QueryPerformance/QueryPerformance' +import { PRESET_CONFIG } from 'components/interfaces/Reports/Reports.constants' +import { useQueryPerformanceQuery } from 'components/interfaces/Reports/Reports.queries' +import { Presets } from 'components/interfaces/Reports/Reports.types' +import { queriesFactory } from 'components/interfaces/Reports/Reports.utils' +import { DatabaseLayout } from 'components/layouts' +import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import { FormHeader } from 'components/ui/Forms' +import { useFlag } from 'hooks' +import type { NextPageWithLayout } from 'types' + +type QueryPerformancePreset = 'time' | 'frequent' | 'slowest' + +const QueryPerformanceReport: NextPageWithLayout = () => { + const router = useRouter() + const { ref: projectRef } = useParams() + + const tableIndexEfficiencyEnabled = useFlag('tableIndexEfficiency') + const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] + const hooks = queriesFactory(config.queries, projectRef ?? 'default') + const queryHitRate = hooks.queryHitRate() + + const orderBy = (router.query.sort as 'lat_desc' | 'lat_asc') || 'lat_desc' + const searchQuery = (router.query.search as string) || '' + const roles = router.query.roles || [] + const presetMap = { + time: 'mostTimeConsuming', + frequent: 'mostFrequentlyInvoked', + slowest: 'slowestExecutionTime', + } as const + const preset = presetMap[router.query.preset as QueryPerformancePreset] || 'mostTimeConsuming' + + const queryPerformanceQuery = useQueryPerformanceQuery({ + searchQuery, + orderBy, + preset, + roles: typeof roles === 'string' ? [roles] : roles, + }) + + const isLoading = [queryPerformanceQuery.isLoading, queryHitRate.isLoading].every( + (value) => value + ) + + return ( + <> + + +
    + + + {tableIndexEfficiencyEnabled && } + +
    +
    +
    + + ) +} + +QueryPerformanceReport.getLayout = (page) => ( + {page} +) + +export default QueryPerformanceReport diff --git a/apps/studio/pages/project/[ref]/database/replication.tsx b/apps/studio/pages/project/[ref]/database/replication.tsx index 68bb20bab86..5b4df2aa27d 100644 --- a/apps/studio/pages/project/[ref]/database/replication.tsx +++ b/apps/studio/pages/project/[ref]/database/replication.tsx @@ -9,6 +9,7 @@ import NoPermission from 'components/ui/NoPermission' import { useDatabasePublicationsQuery } from 'data/database-publications/database-publications-query' import { useCheckPermissions, usePermissionsLoaded } from 'hooks' import type { NextPageWithLayout } from 'types' +import { FormHeader } from 'components/ui/Forms' // [Joshen] Technically, best that we have these as separate URLs // makes it easier to manage state, but foresee that this page might @@ -40,9 +41,7 @@ const DatabaseReplication: NextPageWithLayout = () => {
    -
    -

    Database Replications

    -
    + {selectedPublication === undefined ? ( ) : ( diff --git a/apps/studio/pages/project/[ref]/database/roles.tsx b/apps/studio/pages/project/[ref]/database/roles.tsx index 6d4f48871ad..0ba69c26798 100644 --- a/apps/studio/pages/project/[ref]/database/roles.tsx +++ b/apps/studio/pages/project/[ref]/database/roles.tsx @@ -1,6 +1,7 @@ import { RolesList } from 'components/interfaces/Database' import { DatabaseLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import { FormHeader } from 'components/ui/Forms' import type { NextPageWithLayout } from 'types' const DatabaseRoles: NextPageWithLayout = () => { @@ -8,6 +9,10 @@ const DatabaseRoles: NextPageWithLayout = () => {
    +
    diff --git a/apps/studio/pages/project/[ref]/database/schemas.tsx b/apps/studio/pages/project/[ref]/database/schemas.tsx index 390eea29f1f..4723b20dcef 100644 --- a/apps/studio/pages/project/[ref]/database/schemas.tsx +++ b/apps/studio/pages/project/[ref]/database/schemas.tsx @@ -32,12 +32,12 @@ const SchemasPage: NextPageWithLayout = () => { return ( <>
    -
    +
    {isLoading && (
    )} - {isError && } + {isError && } {isSuccess && ( { const { id } = useParams() const snap = useTableEditorStateSnapshot() - const { data: selectedTable } = useTable(Number(id)) + const { data: selectedTable, isLoading } = useTable(Number(id)) return ( <> -
    +
    +
    + + + {isLoading ? ( + + ) : ( + + )} +
    {
    + { diff --git a/apps/studio/pages/project/[ref]/database/triggers.tsx b/apps/studio/pages/project/[ref]/database/triggers.tsx index 4fd2c098dce..f8daed7cf35 100644 --- a/apps/studio/pages/project/[ref]/database/triggers.tsx +++ b/apps/studio/pages/project/[ref]/database/triggers.tsx @@ -5,6 +5,7 @@ import { CreateTrigger, DeleteTrigger } from 'components/interfaces/Database' import TriggersList from 'components/interfaces/Database/Triggers/TriggersList/TriggersList' import { DatabaseLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import { FormHeader } from 'components/ui/Forms' import NoPermission from 'components/ui/NoPermission' import { useCheckPermissions, usePermissionsLoaded } from 'hooks' import type { NextPageWithLayout } from 'types' @@ -41,7 +42,7 @@ const TriggersPage: NextPageWithLayout = () => {
    -

    Database Triggers

    + { return ( - <> - - - -

    Database Enumerated Types

    -

    - Custom data types that you can use in your database tables or functions. -

    -
    - -
    - -
    -
    -
    - -
    -
    -
    - + + + + + + + + +
    + +
    +
    +
    ) } diff --git a/apps/studio/pages/project/[ref]/database/wrappers/index.tsx b/apps/studio/pages/project/[ref]/database/wrappers/index.tsx index 7b18ac978df..b1ed00123fc 100644 --- a/apps/studio/pages/project/[ref]/database/wrappers/index.tsx +++ b/apps/studio/pages/project/[ref]/database/wrappers/index.tsx @@ -1,31 +1,85 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' +import { ExternalLink } from 'lucide-react' import { Wrappers } from 'components/interfaces/Database' +import WrappersDropdown from 'components/interfaces/Database/Wrappers/WrappersDropdown' import { DatabaseLayout } from 'components/layouts' -import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' +import { + ScaffoldContainer, + ScaffoldSection, + ScaffoldSectionContent, + ScaffoldSectionDetail, +} from 'components/layouts/Scaffold' +import { FormHeader } from 'components/ui/Forms' import NoPermission from 'components/ui/NoPermission' +import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' +import { useFDWsQuery } from 'data/fdw/fdws-query' import { useCheckPermissions, usePermissionsLoaded } from 'hooks' import type { NextPageWithLayout } from 'types' +import { Button } from 'ui' +import { GenericSkeletonLoader } from 'ui-patterns' const DatabaseWrappers: NextPageWithLayout = () => { - const canReadWrappers = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'tables') + const { project } = useProjectContext() const isPermissionsLoaded = usePermissionsLoaded() + const canReadWrappers = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'tables') - if (isPermissionsLoaded && !canReadWrappers) { - return - } + const { isLoading: isLoadingFDWs } = useFDWsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + }) + const { data: exts, isLoading: isLoadingExtensions } = useDatabaseExtensionsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + }) + const wrappersExtension = (exts ?? []).find((ext) => ext.name === 'wrappers') + const vaultExtension = (exts ?? []).find((ext) => ext.name === 'supabase_vault') - return -} + const isWrappersEnabled = + wrappersExtension !== undefined && + wrappersExtension.installed_version !== null && + vaultExtension !== undefined && + vaultExtension.installed_version !== null -DatabaseWrappers.getLayout = (page) => ( - + return ( -
    {page}
    + + + + + + {isWrappersEnabled && } + + +
    + {isLoadingExtensions || isLoadingFDWs ? ( + + ) : isPermissionsLoaded && !canReadWrappers ? ( + + ) : ( + + )} +
    -
    -) + ) +} + +DatabaseWrappers.getLayout = (page) => {page} export default DatabaseWrappers diff --git a/apps/studio/pages/project/[ref]/reports/api-overview.tsx b/apps/studio/pages/project/[ref]/reports/api-overview.tsx index 3e3abb54d1b..6774133f4ea 100644 --- a/apps/studio/pages/project/[ref]/reports/api-overview.tsx +++ b/apps/studio/pages/project/[ref]/reports/api-overview.tsx @@ -42,7 +42,7 @@ export const ApiReport: NextPageWithLayout = () => { return ( - +
    { - const router = useRouter() - const { ref: projectRef } = useParams() - const { project } = useProjectContext() - const [showResetgPgStatStatements, setShowResetgPgStatStatements] = useState(false) - - const tableIndexEfficiencyEnabled = useFlag('tableIndexEfficiency') - const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] - const hooks = queriesFactory(config.queries, projectRef ?? 'default') - const queryHitRate = hooks.queryHitRate() - - const orderBy = (router.query.sort as 'lat_desc' | 'lat_asc') || 'lat_desc' - const searchQuery = (router.query.search as string) || '' - const presetMap = { - time: 'mostTimeConsuming', - frequent: 'mostFrequentlyInvoked', - slowest: 'slowestExecutionTime', - } as const - const preset = presetMap[router.query.preset as QueryPerformancePreset] || 'mostTimeConsuming' - - const queryPerformanceQuery = useQueryPerformanceQuery({ - searchQuery, - orderBy, - preset, - }) - - const isLoading = [queryPerformanceQuery.isLoading, queryHitRate.isLoading].every( - (value) => value - ) - - const handleRefresh = async () => { - queryPerformanceQuery.runQuery() - queryHitRate.runQuery() - } - - const checkAlert = ( -
    - -
    - ) - const warnAlert = ( -
    - -
    - ) - const dangerAlert = ( -
    - -
    - ) - - const indexHitRate = queryHitRate.data?.[0]?.ratio - const tableHitRate = queryHitRate.data?.[1]?.ratio - const showIndexWarning = - indexHitRate && tableHitRate && (indexHitRate <= 0.99 || tableHitRate <= 0.99) - - const headerText = ( -

    - Identify the queries that consume the most time and database resources. - {'\n\n'}It relies on the pg_stat_statements table. Read more about{' '} - - examining query performance - - .{'\n\n'}Consider resetting the analysis after optimizing any queries. -

    - ) - - const TimeConsumingHelperText = `This table lists queries ordered by their cumulative total execution time. - - It displays the total time a query has spent running and the proportion of total execution time the query has consumed. -` - - const MostFrequentHelperText = `This table lists queries in order of their execution count, providing insights into the most frequently executed queries. - - Pay attention to queries with high max_time or mean_time values that are called frequently, as they may benefit from optimization. -` - - const SlowestExecutionHelperText = `This table lists queries ordered by their maximum execution time. It shows outliers with high execution times. Queries with long execution times may benefit from optimization. - - Look for queries with high or mean execution times. These are often good candidates for optimization. -` - const panelClassNames = 'text-sm max-w-none flex flex-col gap-8 py-4' - const helperTextClassNames = 'prose text-sm max-w-2xl text-foreground-light' - - return ( -
    - - {tableIndexEfficiencyEnabled && ( - - - Index Efficiency - {showIndexWarning ? warnAlert : checkAlert} -
    - } - id="1" - className="flex flex-row gap-8" - > - {!isLoading && queryHitRate && ( -
    -
    -
    - Index Hit Rate -
    - {indexHitRate >= 0.99 - ? checkAlert - : indexHitRate >= 0.95 - ? warnAlert - : dangerAlert} -
    - - {queryHitRate?.data && (queryHitRate?.data[0]?.ratio * 100).toFixed(2)} - - % -
    -
    -
    - -
    - {queryHitRate?.data![1]?.name == 'table hit rate' && 'Table Hit Rate'} -
    - {tableHitRate >= 0.99 - ? checkAlert - : tableHitRate >= 0.95 - ? warnAlert - : dangerAlert} -
    - - {queryHitRate?.data && (queryHitRate?.data[1]?.ratio * 100).toFixed(2)} - - % -
    -
    -
    -
    -
    -

    - For best performance, ensure that the cache hit rate ratios above 99%.
    {' '} - Consider upgrading to an instance with more memory if the ratios dip below 95%. -

    -
    -
    - )} - - - )} - - {headerText} - -
    - -
    - - setShowResetgPgStatStatements(false)} - onSelectConfirm={async () => { - try { - await executeSql({ - projectRef: project?.ref, - connectionString: project?.connectionString, - sql: `SELECT pg_stat_statements_reset();`, - }) - setShowResetgPgStatStatements(false) - handleRefresh() - } catch (error) { - console.error(error) - } - }} - /> - -
    - { - // To reset the search and sort query params when switching tabs - const { sort, search, ...rest } = router.query - router.push({ - ...router, - query: { - ...rest, - preset: e, - }, - }) - }} - > - -
    - - {TimeConsumingHelperText} - -
    - -
    - Role - Query - Calls - Time Consumed - Total Time (Latency) - - } - body={ - !queryPerformanceQuery.isLoading ? ( - queryPerformanceQuery?.data?.map((item, i) => { - return ( - - - {item.rolname} - - -

    {item.query}

    -
    - {item.calls} - - {item.prop_total_time} - - - {item.total_time.toFixed(2)}ms - -
    - ) - }) - ) : ( - - ) - } - /> - - - - -
    - - {MostFrequentHelperText} - -
    - -
    - Role - Query - Avg. Roles - Calls - Max Time - Mean Time - Min Time - Total Time (Latency) - - } - body={ - queryPerformanceQuery.isLoading ? ( - - ) : ( - queryPerformanceQuery.data?.map((item, i) => { - return ( - - - {item.rolname} - - -

    {item.query}

    -
    - {item.avg_rows} - {item.calls} - - {item.max_time?.toFixed(2)}ms - - - {item.mean_time?.toFixed(2)}ms - - - {item.min_time?.toFixed(2)}ms - - - {item.total_time?.toFixed(2)}ms - -
    - ) - }) - ) - } - /> - - - - -
    - - {SlowestExecutionHelperText} - -
    - -
    - Role - Query - Avg Rows - Calls - Max Time - Mean Time - Min Time - Total Time (Latency) - - } - body={ - queryPerformanceQuery.isLoading ? ( - - ) : ( - queryPerformanceQuery.data?.map((item, i) => { - return ( - - - {item.rolname} - - -

    {item.query}

    -
    - {item.avg_rows} - {item.calls} - {item.max_time?.toFixed(2)}ms - {item.mean_time?.toFixed(2)}ms - {item.min_time?.toFixed(2)}ms - - {item.total_time?.toFixed(2)}ms - -
    - ) - }) - ) - } - /> - - - - - - - ) -} - -QueryPerformanceReport.getLayout = (page) => ( - {page} -) - -export default QueryPerformanceReport - -function QueryPerformanceFilterBar({ - isLoading, - onRefreshClick, -}: { - isLoading: boolean - onRefreshClick: () => void -}) { - const router = useRouter() - const defaultSearchQueryValue = router.query.search ? String(router.query.search) : '' - const defaultSortByValue = router.query.sort ? String(router.query.sort) : 'lat_desc' - const [searchInputVal, setSearchInputVal] = useState(defaultSearchQueryValue) - const [sortByValue, setSortByValue] = useState(defaultSortByValue) - - function getSortButtonLabel() { - const sort = router.query.sort as 'lat_desc' | 'lat_asc' - - if (sort === 'lat_desc') { - return 'Sorted by latency - high to low' - } else { - return 'Sorted by latency - low to high' - } - } - - function onSortChange(sort: string) { - setSortByValue(sort) - router.push({ - ...router, - query: { - ...router.query, - sort, - }, - }) - } - - const ButtonIcon = sortByValue === 'lat_desc' ? IconArrowDown : IconArrowUp - - return ( - <> -
    - { - e.preventDefault() - const formData = new FormData(e.target as HTMLFormElement) - const searchQuery = formData.get('search') - - if (!searchQuery || typeof searchQuery !== 'string') { - // if user has deleted the search query, remove it from the url - const { search, ...rest } = router.query - router.push({ - ...router, - query: { - ...rest, - }, - }) - return - } - - router.push({ - ...router, - query: { - ...router.query, - search: searchQuery, - }, - }) - }} - > - setSearchInputVal(e.target.value)} - autoComplete="off" - icon={ -
    - -
    - } - actions={ - searchInputVal !== '' && ( - - ) - } - /> - - - - - - - - Sort by latency - high to low - - - Sort by latency - low to high - - - - - -
    - -
    -
    - - ) -} - -function QueryPerformanceLoadingRow({ colSpan }: { colSpan: number }) { - return ( - <> - {Array(4) - .fill('') - .map((_, i) => ( -
    - - - ))} - - ) -} diff --git a/apps/studio/pages/project/[ref]/reports/storage.tsx b/apps/studio/pages/project/[ref]/reports/storage.tsx index 330f41e045f..1a1da3f76c9 100644 --- a/apps/studio/pages/project/[ref]/reports/storage.tsx +++ b/apps/studio/pages/project/[ref]/reports/storage.tsx @@ -45,7 +45,7 @@ export const StorageReport: NextPageWithLayout = () => { return ( - +
    {

    Link Vercel to Supabase

    Choose which of your Vercel projects to link to your existing Supabase projects.

    - +

    Vercel Projects

    @@ -449,7 +448,7 @@ const ProjectLinks = observer(() => {

    Supabase Projects

    - +
    {displayButton()}
    diff --git a/apps/studio/public/favicon/browserconfig.xml b/apps/studio/public/favicon/browserconfig.xml index c5541482230..1a8136def88 100644 --- a/apps/studio/public/favicon/browserconfig.xml +++ b/apps/studio/public/favicon/browserconfig.xml @@ -1,2 +1,2 @@ -#ffffff \ No newline at end of file +#ffffff \ No newline at end of file diff --git a/apps/studio/public/favicon/favicon-180x180.png b/apps/studio/public/favicon/favicon-180x180.png new file mode 100644 index 00000000000..456f3c7dd9d Binary files /dev/null and b/apps/studio/public/favicon/favicon-180x180.png differ diff --git a/apps/studio/public/favicon/favicon-48x48.png b/apps/studio/public/favicon/favicon-48x48.png new file mode 100644 index 00000000000..eb6a7ec729a Binary files /dev/null and b/apps/studio/public/favicon/favicon-48x48.png differ diff --git a/apps/studio/public/favicon/manifest.json b/apps/studio/public/favicon/manifest.json index 3a90d23e45e..4efcf18e2ec 100644 --- a/apps/studio/public/favicon/manifest.json +++ b/apps/studio/public/favicon/manifest.json @@ -7,37 +7,37 @@ "background_color": "#1C1C1C", "icons": [ { - "src": "/android-icon-36x36.png", + "src": "/favicon/android-icon-36x36.png", "sizes": "36x36", "type": "image/png", "density": "0.75" }, { - "src": "/android-icon-48x48.png", + "src": "/favicon/android-icon-48x48.png", "sizes": "48x48", "type": "image/png", "density": "1.0" }, { - "src": "/android-icon-72x72.png", + "src": "/favicon/android-icon-72x72.png", "sizes": "72x72", "type": "image/png", "density": "1.5" }, { - "src": "/android-icon-96x96.png", + "src": "/favicon/android-icon-96x96.png", "sizes": "96x96", "type": "image/png", "density": "2.0" }, { - "src": "/android-icon-144x144.png", + "src": "/favicon/android-icon-144x144.png", "sizes": "144x144", "type": "image/png", "density": "3.0" }, { - "src": "/android-icon-192x192.png", + "src": "/favicon/android-icon-192x192.png", "sizes": "192x192", "type": "image/png", "density": "4.0" diff --git a/apps/studio/styles/ui.scss b/apps/studio/styles/ui.scss index b2e37296cc0..334d4fd1c87 100644 --- a/apps/studio/styles/ui.scss +++ b/apps/studio/styles/ui.scss @@ -1,8 +1,3 @@ -.dark .sbui-default-button--dark-white { - @apply shadow-md text-typography-body-light border-gray-50 bg-white #{!important}; - text-shadow: none !important; -} - /* Brought over from platform to be cleaned if needed */ /* Form panels */ @@ -441,4 +436,3 @@ @apply stroke-foreground-lighter; } } - diff --git a/apps/studio/types/base.ts b/apps/studio/types/base.ts index 373b42ace45..23c593e2307 100644 --- a/apps/studio/types/base.ts +++ b/apps/studio/types/base.ts @@ -1,5 +1,5 @@ -import jsonLogic from 'json-logic-js' import { PermissionAction } from '@supabase/shared-types/out/constants' +import jsonLogic from 'json-logic-js' export interface Organization { id: number @@ -10,6 +10,8 @@ export interface Organization { stripe_customer_id?: string opt_in_tags: string[] subscription_id?: string | null + restriction_status: 'grace_period' | 'grace_period_over' | 'restricted' | null + restriction_data: Record } /** @@ -88,7 +90,7 @@ export interface ResponseFailure { export type SupaResponse = T | ResponseFailure export interface ResponseError { - code?: number + code?: number | string message: string requestId?: string } diff --git a/apps/www/_blog/2023-12-13-supavisor-postgres-connection-pooler.mdx b/apps/www/_blog/2023-12-13-supavisor-postgres-connection-pooler.mdx index 04d487edb73..a3687d25628 100644 --- a/apps/www/_blog/2023-12-13-supavisor-postgres-connection-pooler.mdx +++ b/apps/www/_blog/2023-12-13-supavisor-postgres-connection-pooler.mdx @@ -87,18 +87,18 @@ For the Supavisor rollout, we maintained consistent pooling settings between PgB Now, we're raising the client connection limit for smaller projects in Supavisor. Here are the updated default configurations: -| Database Size | default_pool_size | max_connections | default_max_clients | -| ------------- | ----------------- | --------------- | --------------------- | -| micro | 15 | 60 | 200 | -| small | 15 | 90 | 1000 (previously 200) | -| medium | 15 | 120 | 1000 (previously 200) | -| large | 15 | 160 | 1000 (previously 300) | -| xl | 20 | 240 | 1000 (previously 700) | -| 2xl | 25 | 380 | 1500 | -| 4xl | 32 | 480 | 3000 | -| 8xl | 64 | 490 | 6000 | -| 12xl | 96 | 500 | 9000 | -| 16xl | 128 | 500 | 12000 | +| Database Size | default_pool_size | max_connections | default_max_clients | +| ------------- | ----------------- | --------------- | ---------------------- | +| Micro | 15 | 60 | 200 | +| Small | 15 | 90 | 400 (previously 200) | +| Medium | 15 | 120 | 600 (previously 200) | +| Large | 20 | 160 | 800 (previously 300) | +| XL | 20 | 240 | 1,000 (previously 700) | +| 2XL | 25 | 380 | 1,500 | +| 4XL | 32 | 480 | 3,000 | +| 8XL | 64 | 490 | 6,000 | +| 12XL | 96 | 500 | 9,000 | +| 16XL | 128 | 500 | 12,000 | In this table: diff --git a/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx b/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx index 8640a76f8c2..51c2c615d3f 100644 --- a/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx +++ b/apps/www/_blog/2024-01-26-flutter-figma-clone.mdx @@ -860,6 +860,8 @@ This article only used circles and rectangles to keep things simple, but you can ## Resources -- [Create live cursor app with Flutter and Supabase video](https://www.youtube.com/watch?v=QhRNXlFLaeE) +- [Add live cursor sharing using Flutter and Supabase | Flutter Figma Clone #1](https://youtu.be/QhRNXlFLaeE?si=_hi5WcILUsAv8jJY) +- [Draw and sync canvas in real-time | Flutter Figma Clone #2](https://youtu.be/zKjrmAMf2Cs?si=i7zILCFKitjDb45K) +- [Track online users with Supabase Realtime Presence | Flutter Figma Clone #3](https://youtu.be/B2NZvZ2uLNs?si=0rMj7u1gaMH9Bmdm) - [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game) - [Getting started with Flutter authentication](https://supabase.com/blog/flutter-authentication) diff --git a/apps/www/_blog/2024-04-01-pg-paper-dump.mdx b/apps/www/_blog/2024-04-01-pg-paper-dump.mdx new file mode 100644 index 00000000000..e7ba9c8f17d --- /dev/null +++ b/apps/www/_blog/2024-04-01-pg-paper-dump.mdx @@ -0,0 +1,68 @@ +--- +title: Announcing Data Preservation Service +description: Secure, reliable and timeless backups +author: long +image: 2024-04-01-pg-paper-dump/pg-paper-dump-thumb.png +thumb: 2024-04-01-pg-paper-dump/pg-paper-dump-thumb.png +categories: + - company +tags: + - announcements +date: '2024-04-01' +toc_depth: 3 +--- + +We live in a world where data is as critical as air and water, powering everything from global enterprises to personal projects. At Supabase, we create products that are not just cutting-edge but also secure, reliable, and now, timeless. + +Today, we are excited to introduce a groundbreaking service that bridges the digital divide with the most enduring medium known to humankind: paper. Meet [pg_paper_dump](https://github.com/supabase-community/pg_paper_dump), Supabase’s answer to the ultimate data preservation conundrum. + +## Why Paper? + +In the digital era, the threat landscape is constantly evolving, with new vulnerabilities emerging at a pace that's hard to keep up with. While digital backups are the norm, they are susceptible to cyber-attacks, hardware failures, and obsolescence. + +This vulnerability led us to think outside the digital box and into a realm that is impervious to hacking, immune to electromagnetic pulses, and resistant to time itself: physical paper. + +![Historical Paper Backup on Papyrus](/images/blog/2024-04-01-pg-paper-dump/historical-paper-backup.webp) + +Historical data backup on Papyrus that inspired `pg_paper_dump`. + +## How does `pg_paper_dump` work? + +### Backup Process + +1. **Select Your Data:** Choose the databases you wish to back up with `pg_paper_dump`. +2. **Encode and Print:** Our system encodes your data with Comic Sans and prints it onto durable paper. +3. **Secure Storage:** We store your paper backups in a location of your choice or utilize our secure Arctic Vault for maximum security. + +### Restoration Process + +1. **Select your recovery point:** Thanks to point-in-time recovery, we can restore your data up until any specific page. +2. **Restore:** Our Mechanical Turks are trained to decode data encoded in Comic Sans and will input your data with reasonable human-accuracy into your destination database. + +### Scaling data preservation with containers + +Our Analog Engineering team has developed a container orchestration protocol to coordinate the backup and restore process of large databases. + +![Scaling analog data preservation with container orchetration](/images/blog/2024-04-01-pg-paper-dump/paper-container.jpeg) + +## Who is pg_paper_dump for? + +- Companies that use fax machines. +- Future SOC 4 compliant companies. +- [Vogons](https://en.m.wikipedia.org/wiki/Vogon). + +## Features and Benefits + +- **Security:** Provides a level of security that is fundamentally beyond the reach of digital vulnerabilities. +- **Eco-conscious:** Our materials are selected for minimal environmental impact without compromising on durability or legibility. +- **Simplicity of Restoration:** When the time comes, restoring your data is as simple as taking the printed codes and typing them back into Supabase’s SQL editor. + +## Availability + +[Sign up](https://forms.supabase.com/pg-paper-dump) for our open beta to get access to `pg_paper_dump` now or try it out our self-hosted solution. + +As all of our products, we have open-sourced the code and made it available to the public to be used without any restrictions [here](https://github.com/supabase-community/pg_paper_dump). + +## The Future is Here + +We are offering a bridge between these worlds, providing a backup solution that stands the test of time. Join us in redefining data security and making history, one sheet at a time. diff --git a/apps/www/components/Footer/index.tsx b/apps/www/components/Footer/index.tsx index f14c03d8f50..38f57d975d0 100644 --- a/apps/www/components/Footer/index.tsx +++ b/apps/www/components/Footer/index.tsx @@ -20,7 +20,7 @@ const Footer = (props: Props) => { const { resolvedTheme } = useTheme() const { pathname } = useRouter() - const isLaunchWeek = pathname.includes('launch-week') + const isLaunchWeek = pathname.includes('launch-week') || pathname.includes('special-announcement') const forceDark = isLaunchWeek || pathname === '/' if (props.hideFooter) { diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx index a6082ccfe61..492834269e2 100644 --- a/apps/www/components/Hero/Hero.tsx +++ b/apps/www/components/Hero/Hero.tsx @@ -6,6 +6,7 @@ import gaEvents from '~/lib/gaEvents' import { Button, IconBookOpen } from 'ui' import SectionContainer from '~/components/Layouts/SectionContainer' import HeroFrameworks from './HeroFrameworks' +import AnnouncementBadge from '../Announcement/Badge' const Hero = () => { const router = useRouter() @@ -22,13 +23,13 @@ const Hero = () => {
    - {/*
    +
    -
    */} +

    Build in a weekend diff --git a/apps/www/components/LaunchWeek/11/Countdown.tsx b/apps/www/components/LaunchWeek/11/Countdown.tsx new file mode 100644 index 00000000000..d0a61eb6c30 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Countdown.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import Countdown from 'react-countdown' +import { CountdownWidget } from 'ui-patterns/CountdownWidget' + +const CountdownComponent = ({ + date, + showCard = true, + className, + size = 'small', +}: { + date: string | number | Date + showCard?: boolean + className?: string + size?: 'small' | 'large' +}) => { + if (!date) return null + + const renderer = ({ days, hours, minutes, seconds, completed }: any) => { + if (completed) { + // Render a completed state + return null + } else { + // Render countdown + return ( + + ) + } + } + + return +} + +export default CountdownComponent diff --git a/apps/www/components/LaunchWeek/11/HackathonCallout.tsx b/apps/www/components/LaunchWeek/11/HackathonCallout.tsx new file mode 100644 index 00000000000..e65aae08570 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/HackathonCallout.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { TextLink, cn } from 'ui' + +const HackathonCallout = ({ className }: { className?: string }) => { + return ( +
    +
    + Join the Hackathon +
    +
    + +
    +
    + ) +} + +export default HackathonCallout diff --git a/apps/www/components/LaunchWeek/11/LW11Background/Dot.js b/apps/www/components/LaunchWeek/11/LW11Background/Dot.js new file mode 100644 index 00000000000..489ad673d4b --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Background/Dot.js @@ -0,0 +1,20 @@ +export function Dot(x, y, w, h, opacity, animationConfig, color = '255,255,255') { + this.x = x + this.y = y + this.w = w + this.h = h + this.opacity = opacity + this.anim = animationConfig + this.isVert = this.anim?.direction === 'vertical' + + this.draw = function (c) { + c.fillRect(this.x, this.y, this.w, this.h) + c.fillStyle = `rgba(${color},${this.opacity})` + + c.fill() + } + + this.update = function (c, clock) { + this.draw(c, clock) + } +} diff --git a/apps/www/components/LaunchWeek/11/LW11Background/index.tsx b/apps/www/components/LaunchWeek/11/LW11Background/index.tsx new file mode 100644 index 00000000000..ed55f8475da --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Background/index.tsx @@ -0,0 +1,178 @@ +import React, { useEffect, useState } from 'react' +import anime from 'animejs' +import { useWindowSize } from 'react-use' +import { isBrowser } from 'common' +import { Dot } from './Dot' +import { cn } from 'ui' + +const defaultConfig = { + dotGrid: 40, + percentageLarge: 0.98, + percentageAnimated: 0.6, + randomizeLargeDots: 3, + randomizeSmallDots: 0.5, + minSpeed: 1, + maxSpeed: 2, + minOscillation: 1, + maxOscillation: 12, + minDelay: -3000, + maxDelay: 15000, + minDuration: 200, + maxDuration: 10000, +} + +const LW11Background = ({ className }: { className?: string }) => { + const canvasRef = React.useRef(null) + const [size, setSize] = useState({ w: 1200, h: 800 }) + const [config] = useState(defaultConfig) + const [hasInitialized, setHasInitialized] = useState(false) + const Window = useWindowSize() + + const DOT_AREA = config.dotGrid + let c = canvasRef.current?.getContext('2d') + let dotsArray: any[] = [] + + function init() { + if (!c) return + + setHasInitialized(true) + c = canvasRef.current?.getContext('2d')! + c.clearRect(0, 0, size.w, size.h) + dotsArray = [] + const GRID_COLS = Math.floor(size.w / DOT_AREA) + const GRID_ROWS = Math.floor(size.h / DOT_AREA) + + for (let i = 0; i < GRID_COLS; i++) { + for (let j = 0; j < GRID_ROWS; j++) { + const isLarge = Math.random() > config.percentageLarge + const isAnimated = isLarge || Math.random() > config.percentageAnimated + const direction = isAnimated ? (Math.random() > 0.5 ? 'vertical' : 'horizontal') : undefined + const speed = isAnimated ? anime.random(config.minSpeed, config.maxSpeed) : undefined + const opacity = isLarge ? 1 : anime.random(0.4, 1) + const isReverse = isAnimated ? Math.random() > 0.5 : undefined + const oscillation = isAnimated + ? anime.random(config.minOscillation, config.maxOscillation).toFixed() + : undefined + const dotSize = isLarge + ? Math.random() * config.randomizeLargeDots + : Math.random() * config.randomizeSmallDots + const endPos = { + x: anime + .random( + DOT_AREA * 1 - DOT_AREA / 2 + dotSize / 2, + DOT_AREA * 10 - DOT_AREA / 2 + dotSize / 2 + ) + .toFixed(), + y: anime + .random( + DOT_AREA * 1 - DOT_AREA / 2 + dotSize / 2, + DOT_AREA * 10 - DOT_AREA / 2 + dotSize / 2 + ) + .toFixed(), + } + const delay = anime.random(config.minDelay, config.maxDelay) + const duration = anime.random(config.minDuration, config.maxDuration) + const animationConfig: any = isAnimated + ? { + direction, + speed, + isReverse, + oscillation, + endPos, + delay, + duration, + } + : undefined + const x = (size.w / GRID_COLS) * i + DOT_AREA / 2 - dotSize / 2 + const y = (size.h / GRID_ROWS) * j + DOT_AREA / 2 - dotSize / 2 + const w = dotSize + const h = dotSize + + dotsArray.push(new Dot(x, y, w, h, opacity, animationConfig)) + } + } + + animate(0) + } + + function animate(clock?: number) { + if (!isBrowser) return + + for (let i = 0; i < dotsArray.length; i++) { + dotsArray[i].update(c, clock) + } + + const tl = anime + .timeline({ + targets: dotsArray.filter((dot) => dot.anim), + loop: true, + direction: 'alternate', + autoplay: true, + update: renderParticule, + }) + .add( + { + x: (p: any) => + !p.isVert ? `${p.anim?.isReverse ? '+' : '-'}=${DOT_AREA * p.anim.oscillation}` : p.x, + y: (p: any) => + p.isVert ? `${p.anim?.isReverse ? '+' : '-'}=${DOT_AREA * p.anim.oscillation}` : p.y, + duration: (p: any) => p.anim?.duration, + delay: (p: any) => p.anim?.delay - 1000, + easing: 'easeInOutExpo', + }, + '-=1000' + ) + + tl.play() + } + + function renderParticule(anim: any) { + if (!isBrowser) return + + c?.clearRect(0, 0, size.w, size.h) + for (let i = 0; i < dotsArray.length; i++) { + dotsArray[i].update(c, 0) + } + for (var i = 0; i < anim.animatables.length; i++) { + anim.animatables[i].target.update(c, 0) + } + } + + function resize() { + setSize({ w: Window.width, h: Window.height }) + init() + } + + useEffect(() => { + if (!isBrowser) return + resize() + }, [Window]) + + useEffect(() => { + resize() + init() + }, []) + + !hasInitialized && init() + + useEffect(() => { + document.body.classList.add('bg-[#060809]') + + return () => { + if (document.body.classList.contains('bg-[#060809]')) { + document.body.classList.remove('bg-[#060809]') + } + } + }, []) + + return ( + + ) +} + +export default LW11Background diff --git a/apps/www/components/LaunchWeek/11/LW11Day1-v1.tsx b/apps/www/components/LaunchWeek/11/LW11Day1-v1.tsx new file mode 100644 index 00000000000..6726c79b4f0 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Day1-v1.tsx @@ -0,0 +1,79 @@ +import React from 'react' +import Link from 'next/link' +import { ArrowRightIcon } from '@heroicons/react/outline' +import { cn } from 'ui' +import { Edit } from 'lucide-react' +import { WeekDayProps } from './Releases/data' +import { DayLink } from './Releases/components' + +const LW11Day1 = ({ day, className }: { day: WeekDayProps; className?: string }) => { + return ( +
    +
    +
    + {day.dd} {day.date} +
    + + + Blog post + + +
    +
    + {day.description} +
    +
    + {day.steps?.map((step, i) => ( +
    +
    + + + + {step.title} +
    +

    {step.description}

    +
      + {step.links?.map((link) => ( +
    • + +
    • + ))} +
    +
    + ))} +
    +
    + ) +} + +export default LW11Day1 diff --git a/apps/www/components/LaunchWeek/11/LW11Day1.tsx b/apps/www/components/LaunchWeek/11/LW11Day1.tsx new file mode 100644 index 00000000000..174823e23fd --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Day1.tsx @@ -0,0 +1,94 @@ +import React from 'react' +import { cn } from 'ui' +import { ExpandableVideo } from 'ui-patterns' +import { WeekDayProps } from './Releases/data' +import { DayLink } from './Releases/components' + +const LW11Day1 = ({ day, className }: { day: WeekDayProps; className?: string }) => { + const cssGroup = 'group/d' + day.d + + return ( +
    + {/* Day title and links */} +
    +
    + {day.dd}, {day.date} +
    +
    + +

    Supabase is ready for production use.

    +
    + {!!day.links && ( +
      + {day.links?.map((link) => ( +
    • + +
    • + ))} +
    + )} +
    + {/* Card */} +
    +
    + {day.steps?.map((step, i) => ( +
    +
    + + + + {step.title} +
    +

    {step.description}

    +
      + {step.links?.map((link) => ( +
    • + +
    • + ))} +
    +
    + ))} +
    +
    +
    + ) +} + +export default LW11Day1 diff --git a/apps/www/components/LaunchWeek/11/LW11Meetups.tsx b/apps/www/components/LaunchWeek/11/LW11Meetups.tsx new file mode 100644 index 00000000000..1499bdc023a --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Meetups.tsx @@ -0,0 +1,138 @@ +import Link from 'next/link' +import React, { useEffect, useState } from 'react' +import { TextLink, cn } from 'ui' +import useConfData from '../hooks/use-conf-data' +import { SupabaseClient } from '@supabase/supabase-js' + +export interface Meetup { + id?: any + title: string + isLive: boolean + link: string + display_info: string + start_at: string +} + +function addHours(date: Date, hours: number) { + const dateCopy = new Date(date) + + dateCopy.setHours(dateCopy.getHours() + hours) + + return dateCopy +} + +const LW11Meetups = ({ meetups }: { meetups?: Meetup[] }) => { + const { supabase } = useConfData() + const now = new Date(Date.now()) + const [meets, setMeets] = useState(meetups ?? []) + const [realtimeChannel, setRealtimeChannel] = useState | null>(null) + const [activeMeetup, setActiveMeetup] = useState(meets[0]) + const [isMounted, setIsMounted] = useState(false) + + useEffect(() => { + setIsMounted(true) + }, []) + + useEffect(() => { + // Listen to realtime changes + if (supabase && !realtimeChannel) { + const channel = supabase + .channel('lw11_meetups') + .on( + 'postgres_changes', + { + event: '*', + schema: 'public', + table: 'lw11_meetups', + filter: undefined, + }, + async () => { + const { data: newMeets } = await supabase + .from('lw11_meetups') + .select('*') + .neq('isPublished', false) + console.log('newMeets', newMeets) + setMeets( + newMeets?.sort((a, b) => (new Date(a.start_at) > new Date(b.start_at) ? 1 : -1))! + ) + } + ) + .subscribe(async (status) => { + if (status !== 'SUBSCRIBED') { + return null + } + }) + setRealtimeChannel(channel) + } + + return () => { + // Cleanup realtime subscription on unmount + realtimeChannel?.unsubscribe() + } + }, []) + + function handleSelectMeetup(meetup: Meetup) { + setActiveMeetup(meetup) + } + + if (!isMounted) return null + + return ( +
    +
    +

    Community meetups

    +

    + Celebrate{' '} + + Supabase Special Announcement + {' '} + at our live community-driven meetups. Network with the community, listen to tech talks and + grab some swag. +

    + +
    +
    + {meets && + meets + ?.sort((a, b) => (new Date(a.start_at) > new Date(b.start_at) ? 1 : -1)) + .map((meetup: Meetup, i: number) => { + const startAt = new Date(meetup.start_at) + const endAt = addHours(new Date(meetup.start_at), 3) + const after = now > startAt + const before3H = now < endAt + const liveNow = after && before3H + + return ( + handleSelectMeetup(meetup)} + onMouseOver={() => handleSelectMeetup(meetup)} + title={liveNow ? 'Live now' : undefined} + className={cn( + 'h-10 group inline-flex items-center flex-wrap text-4xl', + 'hover:text-[#EDEDED] !leading-none transition-colors', + meetup.id === activeMeetup.id ? 'text-[#EDEDED]' : 'text-[#575E61]', + liveNow && 'text-[#B0B0B0]' + )} + > + {liveNow && ( +
    + )} + {meetup.title} + {i !== meets.length - 1 && ', '} + + ) + })} +
    +
    + {activeMeetup?.display_info} +
    +
    + ) +} + +export default LW11Meetups diff --git a/apps/www/components/LaunchWeek/11/LW11Summary.tsx b/apps/www/components/LaunchWeek/11/LW11Summary.tsx new file mode 100644 index 00000000000..32c1e6a2428 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LW11Summary.tsx @@ -0,0 +1,93 @@ +import React from 'react' +import Image from 'next/image' +import Link from 'next/link' +import { buildDays, mainDays } from './Releases/data' + +const LWXSummary = () => { + return ( +
    +
    + + Launch Week{' '} + + +
    11-15 Dec
    +
    +
    +
    + Main Stage +
    +
      + {mainDays.map( + (day, i: number) => + day.shipped && ( +
        + + + Day {i + 1} - + + {day.description} + +
      + ) + )} +
    +
    +
    +
    +
    + Build Stage +
    +
      + {buildDays.map( + (day, i: number) => + day.is_shipped && ( +
        + + + + {i + 1 < 10 ? '0' : ''} + {i + 1} - + + {day.title} + + +
      + ) + )} +
        + + Supabase Launch Week X Hackathon + +
      +
        + + Supabase Launch Week X Community Meetups + +
      +
    +
    +
    +
    + ) +} + +export default LWXSummary diff --git a/apps/www/components/LaunchWeek/11/LabelBadge.tsx b/apps/www/components/LaunchWeek/11/LabelBadge.tsx new file mode 100644 index 00000000000..889646a39c1 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LabelBadge.tsx @@ -0,0 +1,14 @@ +import React from 'react' + +interface Props { + text: string + className?: string +} + +export default function LabelBadge({ text, className }: Props) { + return ( + + {text} + + ) +} diff --git a/apps/www/components/LaunchWeek/11/LaunchWeekLogoHeader.tsx b/apps/www/components/LaunchWeek/11/LaunchWeekLogoHeader.tsx new file mode 100644 index 00000000000..24dac3579cd --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LaunchWeekLogoHeader.tsx @@ -0,0 +1,16 @@ +export function LaunchWeekLogoHeader() { + return ( +
    +
    +

    Launch week 8

    +

    + August 7th–11th, 2023 +

    +
    +

    A week of announcing new features has come to an end.

    +

    Thanks to everyone who participated.

    +
    +
    +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/LaunchWeekPrizeCard.tsx b/apps/www/components/LaunchWeek/11/LaunchWeekPrizeCard.tsx new file mode 100644 index 00000000000..1b42c15db62 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LaunchWeekPrizeCard.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { cn } from 'ui' +import Panel from '~/components/Panel' + +export default function LaunchWeekPrizeCard({ + content, + className, + contentClassName, +}: { + content: any + className?: string + contentClassName?: string +}) { + return ( + + {content} + + ) +} diff --git a/apps/www/components/LaunchWeek/11/LaunchWeekPrizeSection.tsx b/apps/www/components/LaunchWeek/11/LaunchWeekPrizeSection.tsx new file mode 100644 index 00000000000..3b39b823327 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/LaunchWeekPrizeSection.tsx @@ -0,0 +1,86 @@ +import React from 'react' +import { cn } from 'ui' +import LabelBadge from './LabelBadge' +import LaunchWeekPrizeCard from './LaunchWeekPrizeCard' +import Image from 'next/image' +import PrizeActions from './Releases/PrizeActions' + +export default function LaunchWeekPrizeSection({ className }: { className?: string }) { + return ( +
    +

    Awards

    +

    Generate your ticket for a chance to win.

    +
    +
    + +
    + + +
    +
    +
    + +

    Win AirPods Max

    +

    + Secure your ticket to enter our random prize pool, and amplify your odds by + sharing. Or if you don't leave anything up for chance - join our Hackathon and + showcase your creations. With luck or skill, you could snag these top-tier + headphones! +

    +
    +
    + +
    +
    +
    + } + /> +
    + + +

    Supabase T-shirts

    +
    + } + /> + + +

    Supabase Pins

    +
    + } + /> +
    +
    +

    +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Releases/BuildStage.tsx b/apps/www/components/LaunchWeek/11/Releases/BuildStage.tsx new file mode 100644 index 00000000000..48f6e57ca53 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/BuildStage.tsx @@ -0,0 +1,75 @@ +import React, { FC } from 'react' +import { buildDays as days } from '~/components/LaunchWeek/X/Releases/data' + +import SectionContainer from '~/components/Layouts/SectionContainer' +import AdventCard from './components/AdventCard' +import { motion, useInView } from 'framer-motion' +import { cn } from 'ui' + +const BuildStage: FC = () => { + const ref = React.useRef(null) + const isInView = useInView(ref, { margin: '-25%', once: true }) + + const variants = { + reveal: { + transition: { + type: 'spring', + damping: 10, + mass: 0.75, + stiffness: 100, + staggerChildren: 0.08, + }, + }, + } + + return ( + <> + +

    + Build Stage +

    + + {days.map((day, i) => ( +
  • + + {!day.is_shipped && ( +
    + + + + + +
    + )} +
  • + ))} +
    +
    + + ) +} + +export default BuildStage diff --git a/apps/www/components/LaunchWeek/11/Releases/LW11Header.tsx b/apps/www/components/LaunchWeek/11/Releases/LW11Header.tsx new file mode 100644 index 00000000000..adc385243d8 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/LW11Header.tsx @@ -0,0 +1,20 @@ +import React from 'react' +import { cn } from 'ui' +import SectionContainer from '~/components/Layouts/SectionContainer' +import LW11Background from '../LW11Background' + +const LW11Header = ({ className }: { className?: string }) => { + return ( +
    + + {/* */} +

    + Join us in this major milestone and explore all the features that come with it. +

    +
    + +
    + ) +} + +export default LW11Header diff --git a/apps/www/components/LaunchWeek/11/Releases/LW11StickyNav.tsx b/apps/www/components/LaunchWeek/11/Releases/LW11StickyNav.tsx new file mode 100644 index 00000000000..cc666ba224e --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/LW11StickyNav.tsx @@ -0,0 +1,87 @@ +import React, { FC, useEffect, useRef } from 'react' +import Link from 'next/link' +import { WeekDayProps, mainDays as days } from './data' +import { cn } from 'ui' +import { isBrowser } from 'common' + +import SectionContainer from '~/components/Layouts/SectionContainer' + +const LWXStickyNav: FC = () => { + const OFFSET = 66 + const anchors = useRef | null>(null) + const links = useRef | null>(null) + + const handleScroll = () => { + let newActiveAnchor: string = '' + + anchors.current?.forEach((anchor) => { + const { y: offsetFromTop } = anchor.getBoundingClientRect() + + if (offsetFromTop - OFFSET < 0) { + newActiveAnchor = anchor.id + } + }) + + links.current?.forEach((link) => { + link.classList.remove('!text-foreground') + + const sanitizedHref = decodeURI(link.getAttribute('href') ?? '') + .split('#') + .splice(-1) + .join('') + const isMatch = sanitizedHref === newActiveAnchor + + if (isMatch) { + link.classList.add('!text-foreground') + } + }) + } + + useEffect(() => { + if (!isBrowser) return + anchors.current = document.querySelectorAll('.lwx-nav-anchor') + links.current = document.querySelectorAll('.lwx-sticky-nav li a') + + window.addEventListener('scroll', handleScroll) + return () => { + window.removeEventListener('scroll', handleScroll) + } + }, []) + + return ( +
    + +
    + ) +} + +export default LWXStickyNav diff --git a/apps/www/components/LaunchWeek/11/Releases/MainStage.tsx b/apps/www/components/LaunchWeek/11/Releases/MainStage.tsx new file mode 100644 index 00000000000..e13721e8892 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/MainStage.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import { mainDays } from './data' + +import SectionContainer from '~/components/Layouts/SectionContainer' +import DaySection from './components/DaySection' +import LW11Day1 from '../LW11Day1' +import HackathonCallout from '../HackathonCallout' +import { cn } from 'ui' + +const MainStage = ({ className }: { className?: string }) => { + const [day1, ...days] = mainDays + + return ( + + + +
    + {days.map((day) => ( + + ))} +
    +
    + ) +} + +export default MainStage diff --git a/apps/www/components/LaunchWeek/11/Releases/PrizeActions.tsx b/apps/www/components/LaunchWeek/11/Releases/PrizeActions.tsx new file mode 100644 index 00000000000..45947c24262 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/PrizeActions.tsx @@ -0,0 +1,15 @@ +import Link from 'next/link' +import { Button } from 'ui' + +export default function PrizeActions() { + return ( +
    + + +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Releases/components/AdventCard.tsx b/apps/www/components/LaunchWeek/11/Releases/components/AdventCard.tsx new file mode 100644 index 00000000000..0bb656c6daa --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/components/AdventCard.tsx @@ -0,0 +1,119 @@ +import React, { useEffect, useRef, useState } from 'react' +import Link from 'next/link' +import { motion } from 'framer-motion' +import Tilt from 'vanilla-tilt' +import { useWindowSize } from 'react-use' +import { cn } from 'ui' +import { useBreakpoint } from 'common' + +import { AdventDay } from '../data' +import { AdventLink } from '../data/lw11_build_stage' + +const AdventCard = ({ day, index }: { day: AdventDay; index: number }) => { + const isTablet = useBreakpoint(1024) + const tiltRef = useRef(null) + const hiddenRef = useRef(null) + const { width } = useWindowSize() + const [hiddenHeight, setHiddenHeight] = useState(0) + const transition = { type: 'spring', damping: 10, mass: 0.75, stiffness: 100, delay: index / 15 } + const variants = { + initial: { + rotateY: -90, + opacity: 0, + }, + ...(day.is_shipped && { + reveal: { + rotateY: 0, + opacity: 1, + transition, + }, + }), + } + const isClientLibsCard = day.type === 'clientLibs' + + useEffect(() => { + if (tiltRef.current) { + Tilt.init(tiltRef.current, { + glare: false, + max: isClientLibsCard ? 1 : 4, + gyroscope: false, + 'full-page-listening': false, + }) + } + }, [tiltRef]) + + useEffect(() => { + if (hiddenRef?.current) { + const { height } = hiddenRef.current.getBoundingClientRect() + setHiddenHeight(height) + } + }, [hiddenRef, width]) + + return ( +
    + +
    +
    + {day.icon} +
    +
    +

    {day.title}

    +
    +

    {day.description}

    +
    + {day.links?.map((link: AdventLink) => ( + + {link.label} + + ))} +
    +
    +
    +
    + {isClientLibsCard && ( +
    + {day.icons?.map((link: AdventLink) => ( + + {link.icon} + + ))} +
    + )} +
    +
    + ) +} + +export default AdventCard diff --git a/apps/www/components/LaunchWeek/11/Releases/components/DaySection.tsx b/apps/www/components/LaunchWeek/11/Releases/components/DaySection.tsx new file mode 100644 index 00000000000..0a68dc0a0cb --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/components/DaySection.tsx @@ -0,0 +1,130 @@ +import React from 'react' +import Link from 'next/link' +import Image from 'next/image' +import { ArrowRightIcon } from '@heroicons/react/outline' +import { cn } from 'ui' +import { Edit } from 'lucide-react' +import { useBreakpoint } from 'common' + +import { WeekDayProps } from '../data' +import CountdownComponent from '../../Countdown' +import { DayLink } from '.' + +const DaySection = ({ day }: { day: WeekDayProps }) => { + const isMobile = useBreakpoint(639) + const cssGroup = 'group/d' + day.d + + return ( +
    + {/* Day title and links */} +
    +
    + {day.dd}, {day.date} +
    + {!!day.links && ( +
      + {day.links?.map((link) => ( +
    • + +
    • + ))} +
    + )} +
    + + {/* Day card */} +
    + {day.shipped && day.steps.length > 0 ? ( + +
    +
    + + Blog post + +
    +

    + {day.description} +

    +
    +
    + {day.steps[0]?.bg_layers && + day.steps[0]?.bg_layers?.map( + (layer, i) => + !!layer.img && ( +
    + +
    + ) + )} +
    + + ) : ( +
    +
    + + + + + + {day.hasCountdown && } +
    +
    + )} +
    +
    + ) +} + +export default DaySection diff --git a/apps/www/components/LaunchWeek/11/Releases/components/index.tsx b/apps/www/components/LaunchWeek/11/Releases/components/index.tsx new file mode 100644 index 00000000000..36028c545c8 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/components/index.tsx @@ -0,0 +1,84 @@ +import { useEffect, useState } from 'react' +import { IconDocumentation, IconMicSolid, IconProductHunt, IconYoutubeSolid, cn } from 'ui' +import { Music } from 'lucide-react' + +import Link from 'next/link' +import { StepLink } from '../data/lw11_data' +import { ExpandableVideo } from 'ui-patterns/ExpandableVideo' + +interface DayLink extends StepLink { + className?: string +} + +export const DayLink = ({ type, icon, text, href = '', className }: DayLink) => { + const [isMounted, setIsMounted] = useState(false) + + useEffect(() => { + setIsMounted(true) + }, []) + + if (!isMounted) return null + + const linkTypes = { + blog: { + icon: IconDocumentation, + text: 'Blog Post', + }, + docs: { + icon: IconDocumentation, + text: 'Docs', + }, + productHunt: { + icon: IconProductHunt, + text: 'Product Hunt', + }, + video: { + icon: IconYoutubeSolid, + text: 'Watch video', + }, + podcast: { + icon: Music, + text: 'Podcast', + }, + xSpace: { + icon: IconMicSolid, + text: 'X Space', + }, + } + const isTargetBlank = () => { + switch (type) { + case 'productHunt': + case 'xSpace': + case 'docs': + return true + } + } + const Icon = icon ?? linkTypes[type].icon + const Text = () => <>{text ?? linkTypes[type]?.text} + + const Component = type === 'video' ? 'div' : Link + + const Asd = ({ component: Comp, ...props }: any) => ( + + + + + + + ) + + if (type === 'video') + return } /> + + return +} + +export default { + DayLink, +} diff --git a/apps/www/components/LaunchWeek/11/Releases/data/index.ts b/apps/www/components/LaunchWeek/11/Releases/data/index.ts new file mode 100644 index 00000000000..23d04f18591 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/data/index.ts @@ -0,0 +1,4 @@ +export { default as mainDays } from './lw11_data' +export type { StepProps, StepLink, WeekDayProps } from './lw11_data' +export { days as buildDays } from './lw11_build_stage' +export type { AdventDay } from './lw11_build_stage' diff --git a/apps/www/components/LaunchWeek/11/Releases/data/lw11_build_stage.tsx b/apps/www/components/LaunchWeek/11/Releases/data/lw11_build_stage.tsx new file mode 100644 index 00000000000..edb2274039d --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/data/lw11_build_stage.tsx @@ -0,0 +1,471 @@ +export interface AdventDay { + icon?: any + className?: string + id: string + title: string + description?: string + is_shipped: boolean + links: AdventLink[] + icons?: AdventLink[] + type?: string +} + +export interface AdventLink { + url: string + label?: string + icon?: any + target?: '_blank' +} + +export const days: AdventDay[] = [ + { + title: 'Supabase Album', + description: 'The best soundtrack to build your app in a weekend', + icon: ( + + + + + + ), + id: 'supabase-album', + is_shipped: true, + links: [ + { + url: 'https://supabase.productions/', + label: 'Listen now', + target: '_blank', + }, + ], + }, + { + title: 'Postgres Language Server', + description: 'Implementing the Parser', + icon: ( + + + + + ), + id: 'postgres-language-server-implementing-parser', + is_shipped: true, + links: [ + { + url: '/blog/postgres-language-server-implementing-parser', + label: 'Read blog post', + }, + ], + }, + { + title: 'Design at Supabase', + description: "The transformative journey of Supabase's Design team", + icon: ( + + + + + ), + id: 'design-at-supabase', + is_shipped: true, + links: [ + { + url: '/blog/how-design-works-at-supabase', + label: 'Read blog post', + }, + ], + }, + { + title: 'Supabase Grafana', + description: 'Observability for your Supabase project', + is_shipped: true, + icon: ( + + + + ), + id: 'supabase-grafana', + links: [ + { + url: 'https://github.com/supabase/supabase-grafana', + label: 'View on GitHub', + target: '_blank', + }, + ], + }, + { + title: 'pg_graphql: Postgres functions', + description: 'pg_graphql now supports User Defined Functions (UDFs)', + is_shipped: true, + icon: ( + + + + ), + id: 'pg-graphql-postgres-functions', + links: [ + { + url: '/blog/pg-graphql-postgres-functions', + label: 'Read blog post', + }, + ], + }, + { + title: 'PostgREST 12', + description: 'PostgREST 12 is out: take a look at some of the major new features', + is_shipped: true, + className: 'xl:col-span-2 xl:h-auto xl:aspect-auto', + icon: ( + + + + + ), + id: 'postgrest-12', + links: [ + { + url: '/blog/postgrest-12', + label: 'Read blog post', + }, + ], + }, + { + title: 'Supavisor 1.0', + description: 'A scalable connection pooler for Postgres', + is_shipped: true, + icon: ( + + + + ), + id: 'supavisor', + links: [ + { + url: '/blog/supavisor-postgres-connection-pooler', + label: 'Read blog post', + }, + ], + }, + { + title: 'Supabase Wrappers v0.2', + description: 'Query Pushdown & Remote Subqueries', + is_shipped: true, + icon: ( + + + + ), + id: 'supabase-wrappers-v0.2', + links: [ + { + url: '/blog/supabase-wrappers-v02', + label: 'Read blog post', + }, + ], + }, + { + title: 'Supabase Libraries V2', + description: 'Swift, Kotlin, C#, and Python are now stable and moving to the v2 API', + type: 'clientLibs', + is_shipped: true, + className: 'xl:col-span-2 xl:aspect-auto xl:col-span-3 xl:aspect-auto xl:h-full', + id: 'supabase-libraries-v2', + links: [ + { + url: '/blog/client-libraries-v2', + label: 'Read blog post', + }, + ], + icons: [ + { + url: '/blog/client-libraries-v2#supabase-python-v2', + label: 'Python', + icon: ( + + + + + ), + }, + { + url: '/blog/client-libraries-v2#supabase-swift-v2', + label: 'Swift', + icon: ( + + + + ), + }, + { + url: '/blog/client-libraries-v2#supabase-kotlin-v2', + label: 'Kotlin', + icon: ( + + + + ), + }, + { + url: '/blog/client-libraries-v2#typescript-v2-updates', + label: 'Typescript', + icon: ( + + + + ), + }, + { + url: '/blog/client-libraries-v2#flutter-v2-updates', + label: 'Flutter', + icon: ( + + + + + ), + }, + ], + }, + { + title: 'Supabase x Fly.io', + description: + "We're launching a managed Postgres offering jointly developed by Supabase and Fly.io", + is_shipped: true, + className: 'xl:col-span-2 xl:aspect-auto h-full', + icon: ( + + + + + + + + ), + id: 'fly-postgres', + links: [ + { + url: '/blog/postgres-on-fly-by-supabase', + label: 'Read blog post', + }, + ], + }, + { + title: 'Top 10 Launches of LWX', + description: 'Our CEO takes a look at his favorite ships from LWX', + className: 'sm:aspect-[2/1] sm:col-span-1 sm:col-span-2 sm:aspect-[2/1] h-full', + is_shipped: true, + icon: ( + + + + + ), + id: 'launch-week-x-best-launches', + links: [ + { + url: '/blog/launch-week-x-best-launches', + label: 'Read blog post', + }, + ], + }, +] diff --git a/apps/www/components/LaunchWeek/11/Releases/data/lw11_data.tsx b/apps/www/components/LaunchWeek/11/Releases/data/lw11_data.tsx new file mode 100644 index 00000000000..c5084999db7 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Releases/data/lw11_data.tsx @@ -0,0 +1,305 @@ +import { ReactNode } from 'react' +import { products } from 'shared-data/products' + +type StepLinkType = 'productHunt' | 'video' | 'docs' | 'xSpace' | 'blog' | 'podcast' + +export interface StepLink { + type: StepLinkType + text?: string + icon?: any + href: string +} + +export interface StepProps { + title: string + icon?: string + badge?: string + blog?: string + docs?: string + description?: string + github?: string + hackernews?: string + product_hunt?: string + thumb?: string + url?: string + video?: string + twitter_spaces?: string + className?: string + hideInBlog?: boolean + bg_layers?: { + img?: string + mobileImg?: string + className?: string + }[] + steps?: StepProps[] | [] + links?: StepLink[] +} + +export interface WeekDayProps { + id: string + title: string + shipped: boolean + date: string + published_at: string + isToday?: boolean + hasCountdown?: boolean + description: string | ReactNode + d: number + dd: string + links?: StepLink[] + videoId?: string + videoThumbnail?: string + blog: string + steps: StepProps[] | [] +} + +export const endOfLWXHackathon = '2024-04-17T23:59:59.999-08:00' + +const days: WeekDayProps[] = [ + { + id: 'day-1', + d: 1, + dd: 'Mon', + title: 'Lorem ipsum', + shipped: true, + isToday: false, + blog: '#', + hasCountdown: true, + date: '15 April', + published_at: '2024-04-15T08:00:00.000-08:00', + videoThumbnail: '/images/launchweek/copple-placeholder.jpg', + links: [ + { + type: 'blog', + href: '#', + }, + { + type: 'xSpace', + href: '', + }, + ], + description: ( + <> +

    Our products are now ready for production use.

    {' '} +

    + Confidently leverage the full power of Supabase to build scalable, high-performance + applications with ease. +

    + + ), + steps: [ + { + icon: products.database.icon[16], + title: 'Database', + description: 'Fully portable Postgres Database', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/database/overview', + }, + ], + }, + { + icon: products.authentication.icon[16], + title: 'Auth', + description: 'User management out of the box', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/auth', + }, + ], + }, + { + icon: products.storage.icon[16], + title: 'Storage', + description: 'Serverless storage for any media', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/storage', + }, + ], + }, + { + icon: products.functions.icon[16], + title: 'Edge Functions', + description: 'Deploy code globally on the edge', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/functions', + }, + ], + }, + { + icon: products.realtime.icon[16], + title: 'Realtime', + description: 'Syncronize and broadcast events', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/realtime', + }, + ], + }, + { + icon: products.vector.icon[16], + title: 'Vector', + description: 'AI toolkit to manage embeddings', + links: [ + // { + // type: 'podcast', + // href: '#', + // }, + { + type: 'docs', + href: 'https://supabase.com/docs/guides/ai', + }, + ], + }, + ], + }, + { + id: 'day-2', + d: 2, + dd: 'Tue', + title: '', + shipped: false, + hasCountdown: false, + blog: '#', + date: '16 April', + published_at: '2024-04-16T08:00:00.000-08:00', + description: <>TBD, + links: [ + // { + // type: 'blog', + // href: '#', + // }, + // { + // type: 'video', + // href: 'eCbiywoDORw', + // }, + // { + // type: 'xSpace', + // href: '#', + // }, + ], + steps: [ + { + title: '', + blog: '#', + bg_layers: [ + { + img: '/images/launchweek/lwx/day2/d2_edge.svg', + mobileImg: '/images/launchweek/lwx/day2/d2_edge_mobile.svg', + }, + ], + steps: [], + }, + ], + }, + { + id: 'day-3', + d: 3, + dd: 'Wed', + title: '', + shipped: false, + hasCountdown: false, + blog: '#', + date: '17 April', + published_at: '2024-04-17T08:00:00.000-08:00', + description: <>TBD, + links: [ + // { + // type: 'blog', + // href: '#', + // }, + // { + // type: 'video', + // href: '', + // }, + // { + // type: 'xSpace', + // href: '#', + // }, + ], + steps: [], + }, + { + id: 'day-4', + d: 4, + dd: 'Thu', + title: '', + shipped: false, + hasCountdown: false, + blog: '#', + date: '18 April', + published_at: '2024-04-18T08:00:00.000-08:00', + description: <>TBD, + links: [ + // { + // type: 'blog', + // href: '#', + // }, + // { + // type: 'video', + // href: '', + // }, + // { + // type: 'xSpace', + // href: '#', + // }, + ], + steps: [], + }, + { + id: 'day-5', + d: 5, + dd: 'Fri', + title: '', + shipped: false, + hasCountdown: false, + blog: '#', + date: '19 April', + published_at: '2024-04-19T08:00:00.000-08:00', + description: <>TBD, + links: [ + // { + // type: 'blog', + // href: '#', + // }, + // { + // type: 'video', + // href: '', + // }, + // { + // type: 'xSpace', + // href: '#', + // }, + ], + steps: [], + }, +] + +export default days diff --git a/apps/www/components/LaunchWeek/11/Ticket/LW11Game.tsx b/apps/www/components/LaunchWeek/11/Ticket/LW11Game.tsx new file mode 100644 index 00000000000..4e5c3950e7c --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/LW11Game.tsx @@ -0,0 +1,240 @@ +import { Dispatch, SetStateAction, useEffect, useMemo, useRef, useState } from 'react' +import { Button, cn } from 'ui' +import { SITE_ORIGIN } from '~/lib/constants' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import { VALID_KEYS } from '~/components/LaunchWeek/hooks/useLwGame' +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'ui' + +const REGEXP_ONLY_CHARS = '^[a-zA-Z]+$' + +const COMPLIMENTS = [ + 'Congratulations!', + 'You won!', + 'Hurray!', + 'Great job!', + 'Nice job!', + "That's right!", +] + +interface Props { + setIsGameMode: Dispatch> +} + +const LWXGame = ({ setIsGameMode }: Props) => { + const { supabase, userData: user } = useConfData() + const phrase = process.env.NEXT_PUBLIC_LWX_GAME_WORD ?? 'its_just_postgres' + const inputRef = useRef(null) + const winningPhrase = phrase?.split('_').map((word) => word.split('')) + const phraseLength = phrase?.replaceAll('_', '').split('').length + const [gameState, setGameState] = useState<'playing' | 'winner' | 'loading'>('playing') + const [hasKeyDown, setHasKeyDown] = useState(false) + const [value, setValue] = useState('') + const hasWon = gameState === 'winner' + const winningCompliment = useMemo( + () => COMPLIMENTS[Math.floor(Math.random() * COMPLIMENTS.length)], + [] + ) + + function onKeyDown(event: KeyboardEvent) { + const newKey = event.key.toLocaleLowerCase() + + if (!(event.metaKey || event.ctrlKey) && VALID_KEYS.includes(newKey)) { + setHasKeyDown(true) + } + + setTimeout(() => { + setHasKeyDown(false) + }, 100) + } + + useEffect(() => { + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, [onKeyDown]) + + async function handleGithubSignIn() { + const redirectTo = `${SITE_ORIGIN}/launch-week/${ + user.username ? '?referral=' + user.username : '' + }` + + supabase?.auth.signInWithOAuth({ + provider: 'github', + options: { + redirectTo, + }, + }) + } + const handleClaimTicket = async (e: any) => { + e.preventDefault() + + setGameState('loading') + + if (supabase) { + if (user.id) { + await supabase + .from('lw11_tickets') + .update({ gameWonAt: new Date() }) + .eq('username', user.username) + .then((res) => { + if (res.error) return console.log('error', res.error) + setIsGameMode(false) + }) + } else { + localStorage.setItem('lw11_secret', 'true') + + handleGithubSignIn() + } + } + } + + function handleIndexCount(word_idx: number, char_idx: number) { + let index = -1 + + for (let i = 0; i < word_idx + 1; i++) { + const word = winningPhrase[i] + for (let j = 0; j < word.length; j++) { + if (i < word_idx || j <= char_idx) index++ + } + } + + return index + } + + if (gameState === 'loading') + return ( +
    + + + +
    + ) + + return ( +
    +
    +
    +

    + {winningCompliment} +

    +

    + Claim and share the secret ticket to boost your chances of winning swag. +

    +
    +
    + Guess the word +
    +
    +
    + { + // @ts-ignore + const index = inputRef.current?.dataset.inputOtpMss + const valueAtPhraseIndex = phrase?.replaceAll('_', '').split('')[index] + const currentVal = e.split('')[e.length - 1] + const isMatch = valueAtPhraseIndex === currentVal + + if (isMatch) { + setValue(e) + } + }} + onComplete={() => setGameState('winner')} + > + {winningPhrase.map((word, w_idx) => ( + <> + + {word.map((_, c_idx) => { + // index is sum of every letter of every previous word + index of current wo + const currentIndex = handleIndexCount(w_idx, c_idx) + return ( + + ) + })} + + {w_idx !== winningPhrase.length - 1 && } + + ))} + +
    +
    + +
    +
    +
    + + Play +
    +
    + + Exit +
    +
    + + ) +} + +export default LWXGame diff --git a/apps/www/components/LaunchWeek/11/Ticket/Ticket.tsx b/apps/www/components/LaunchWeek/11/Ticket/Ticket.tsx new file mode 100644 index 00000000000..d42c83315bc --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/Ticket.tsx @@ -0,0 +1,115 @@ +import { useEffect, useRef, useState } from 'react' +import Image from 'next/image' +import { cn } from 'ui' +import { Pencil, X } from 'lucide-react' +import Tilt from 'vanilla-tilt' +import { useBreakpoint, useParams } from 'common' + +import Panel from '~/components/Panel' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import TicketProfile from './TicketProfile' +import TicketCustomizationForm from './TicketCustomizationForm' +import TicketNumber from './TicketNumber' + +export default function Ticket() { + const ticketRef = useRef(null) + const { userData: user, showCustomizationForm, setShowCustomizationForm } = useConfData() + const isMobile = useBreakpoint() + const { + platinum = false, + bg_image_id: bgImageId = '1', + secret: hasSecretTicket, + ticketNumber, + } = user + const [imageHasLoaded, setImageHasLoaded] = useState(false) + const params = useParams() + const sharePage = !!params.username + const ticketType = hasSecretTicket ? 'secret' : platinum ? 'platinum' : 'regular' + + const fallbackImg = `/images/launchweek/11/tickets/shape/lw11_ticket_${ticketType}.png` + + const ticketBg = { + regular: { + background: `/images/launchweek/11/tickets/shape/lw11_ticket_regular.png`, + }, + platinum: { + background: `/images/launchweek/11/tickets/shape/lw11_ticket_platinum.png`, + }, + secret: { + background: `/images/launchweek/11/tickets/shape/lw11_ticket_purple.png`, + }, + } + + function handleCustomizeTicket() { + setShowCustomizationForm && setShowCustomizationForm(!showCustomizationForm) + } + + useEffect(() => { + if (ticketRef.current && !window.matchMedia('(pointer: coarse)').matches) { + Tilt.init(ticketRef.current, { + glare: true, + max: 3, + gyroscope: true, + 'max-glare': 0.2, + 'full-page-listening': true, + }) + } + }, [ticketRef]) + + return ( +
    + + + + setImageHasLoaded(true)} + loading="eager" + fill + className={cn( + 'absolute inset-0 object-cover object-right opacity-0 transition-opacity duration-1000', + imageHasLoaded && 'opacity-100', + isMobile && 'object-left-top' + )} + priority + quality={100} + /> + {/* Edit hover button */} + {!sharePage && ( + <> + + +
    +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketContainer.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketContainer.tsx new file mode 100644 index 00000000000..de798cdad21 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketContainer.tsx @@ -0,0 +1,13 @@ +import Ticket from './Ticket' +import TicketCopy from './TicketCopy' + +export default function TicketContainer() { + return ( +
    + +
    + +
    +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketCopy.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketCopy.tsx new file mode 100644 index 00000000000..ae6a2736b84 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketCopy.tsx @@ -0,0 +1,39 @@ +import { useState, useRef } from 'react' +import { SPECIAL_ANNOUNCEMENT_URL } from '~/lib/constants' +import { Check, Copy } from 'lucide-react' +import useConfData from '../../hooks/use-conf-data' + +export default function TicketCopy() { + const { userData } = useConfData() + const { username, platinum, secret } = userData + const [copied, setCopied] = useState(false) + const buttonRef = useRef(null) + const hasSecretTicket = secret + const url = `${SPECIAL_ANNOUNCEMENT_URL}/tickets/${username}?lw=11${ + hasSecretTicket ? '&secret=true' : platinum ? `&platinum=true` : '' + }` + + return ( +
    + +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketCustomizationForm.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketCustomizationForm.tsx new file mode 100644 index 00000000000..e98a6ce89d9 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketCustomizationForm.tsx @@ -0,0 +1,163 @@ +import React, { useEffect, useState } from 'react' +import { Button, Checkbox, Input, cn } from 'ui' +import { Check } from 'lucide-react' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import { useBreakpoint, useDebounce } from 'common' +import { useKey } from 'react-use' + +const TicketCustomizationForm = ({ className }: { className?: string }) => { + const isMobile = useBreakpoint() + const { + supabase, + userData: user, + showCustomizationForm, + setShowCustomizationForm, + } = useConfData() + const defaultFormValues = { + role: user.metadata?.role, + company: user.metadata?.company, + hideAvatar: !!user.metadata?.hideAvatar, + } + const [formData, setFormData] = useState(defaultFormValues) + const [formState, setFormState] = useState<'idle' | 'saved' | 'saving' | 'error'>('idle') + const IS_SAVING = formState === 'saving' + const IS_SAVED = formState === 'saved' + const HAS_ERROR = formState === 'error' + + useKey('Escape', () => setShowCustomizationForm && setShowCustomizationForm(false)) + + const handleInputChange = (name: string, value: string | boolean) => { + setFormData((prev) => ({ ...prev, [name]: value })) + } + + const handleFormSubmit = async () => { + setFormState('saving') + const payload = { + metadata: { + ...user.metadata, + ...formData, + }, + } + + if (supabase) { + await supabase + .from('lw11_tickets') + .update(payload) + .eq('username', user.username) + .then((res) => { + if (res.error) return setFormState('error') + setFormState('saved') + setTimeout(() => { + setFormState('idle') + }, 1200) + }) + } + } + + const debouncedChangeHandler = useDebounce(handleFormSubmit, 1200) + + useEffect(() => { + return () => setShowCustomizationForm && setShowCustomizationForm(false) + }, []) + + return ( +
    { + e.preventDefault() + debouncedChangeHandler() + }} + onSubmit={(e) => { + e.preventDefault() + handleFormSubmit() + }} + > + { + handleInputChange('role', event.target.value) + }} + onFocus={() => + !showCustomizationForm && setShowCustomizationForm && setShowCustomizationForm(true) + } + inputClassName={cn(IS_SAVING && 'text-foreground-lighter')} + maxLength={25} + icon={ + + } + /> + { + handleInputChange('company', event.target.value) + }} + onFocus={() => + !showCustomizationForm && setShowCustomizationForm && setShowCustomizationForm(true) + } + inputClassName={cn(IS_SAVING && 'text-foreground-lighter')} + icon={ + + } + /> + { + handleInputChange('hideAvatar', event.target.checked) + }} + /> +
    +
    + {IS_SAVED && ( + + Saved + + )} + {HAS_ERROR && ( + + Something went wrong + + )} +
    + +
    + + ) +} + +export default TicketCustomizationForm diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketFooter.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketFooter.tsx new file mode 100644 index 00000000000..04448dc6034 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketFooter.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import TicketNumber from './TicketNumber' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import { cn } from 'ui' + +export default function TicketFooter() { + const { userData: user } = useConfData() + const { ticketNumber, golden, metadata } = user + const hasLightTicket = golden || metadata?.hasSecretTicket + + const SupabaseLogo = hasLightTicket + ? '/images/launchweek/lwx/logos/supabase_lwx_logo_light.png' + : '/images/launchweek/lwx/logos/supabase_lwx_logo_dark.png' + + return ( +
    + {/* */} + + {/* Launch Week X + {LWX_DATE} */} +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketForm.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketForm.tsx new file mode 100644 index 00000000000..60fcdfd439a --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketForm.tsx @@ -0,0 +1,148 @@ +import { useState, useEffect } from 'react' +import { SupabaseClient } from '@supabase/supabase-js' +import { useRouter } from 'next/router' +import { SITE_ORIGIN } from '~/lib/constants' +import { Button } from 'ui' +import { CheckCircle } from 'lucide-react' + +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' + +type FormState = 'default' | 'loading' | 'error' + +export default function TicketForm() { + const [formState, setFormState] = useState('default') + const [realtimeChannel, setRealtimeChannel] = useState | null>(null) + const [errorMsg] = useState('') + const { supabase, session, setUserData, setTicketState, userData } = useConfData() + const router = useRouter() + + // Triggered on session + async function fetchUser() { + if (supabase && session?.user && !userData.id) { + const username = session.user.user_metadata.user_name + const name = session.user.user_metadata.full_name + const email = session.user.email + + await supabase + .from('lw11_tickets') + .insert({ + email, + name, + username, + referred_by: router.query?.referral ?? null, + }) + .eq('email', email) + .select() + .single() + .then(async ({ error }: any) => { + // If error because of duplicate email, ignore and proceed, otherwise sign out. + if (error && error?.code !== '23505') { + setFormState('error') + return supabase.auth.signOut() + } + const { data } = await supabase + .from('lw11_tickets_platinum') + .select('*') + .eq('username', username) + .single() + if (data) { + setUserData(data) + } + + setFormState('default') + + // Prefetch GitHub avatar + new Image().src = `https://github.com/${username}.png` + + // Prefetch the twitter share URL to eagerly generate the page + fetch(`/launch-week/tickets/${username}`).catch((_) => {}) + + if (!realtimeChannel) { + const channel = supabase + .channel('changes') + .on( + 'postgres_changes', + { + event: 'UPDATE', + schema: 'public', + table: 'lw11_tickets', + filter: `username=eq.${username}`, + }, + (payload: any) => { + const platinum = !!payload.new.sharedOnTwitter && !!payload.new.sharedOnLinkedIn + const secret = !!payload.new.gameWonAt + setUserData({ + ...payload.new, + platinum, + secret, + }) + } + ) + .subscribe() + setRealtimeChannel(channel) + } + }) + } + } + + useEffect(() => { + fetchUser() + + return () => { + // Cleanup realtime subscription on unmount + realtimeChannel?.unsubscribe() + } + }, [session]) + + async function handleGithubSignIn() { + if (formState !== 'default') { + setFormState('default') + return + } + + setFormState('loading') + setTicketState('loading') + + const redirectTo = `${SITE_ORIGIN}/launch-week/${ + userData.username ? '?referral=' + userData.username : '' + }` + + supabase?.auth.signInWithOAuth({ + provider: 'github', + options: { + redirectTo, + }, + }) + } + + return formState === 'error' ? ( +
    +
    {errorMsg}
    + +
    + ) : ( +
    + +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketHeader.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketHeader.tsx new file mode 100644 index 00000000000..1cbf1f371f4 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketHeader.tsx @@ -0,0 +1,13 @@ +import React from 'react' + +interface Props { + golden?: boolean +} + +export default function TicketHeader({ golden = false }: Props) { + return ( +
    + Launch Week X +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketNumber.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketNumber.tsx new file mode 100644 index 00000000000..aae10fed0ef --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketNumber.tsx @@ -0,0 +1,31 @@ +import { cn } from 'ui' + +type Props = { + number: number | undefined + secret?: boolean + platinum?: boolean + className?: string +} + +export default function TicketNumber({ + number, + platinum = false, + secret = false, + className, +}: Props) { + const numDigits = `${number}`.length + const prefix = `0000000`.slice(numDigits) + const ticketNumberText = `NO ${prefix}${number}` + + return ( + + {ticketNumberText} + + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketPresence.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketPresence.tsx new file mode 100644 index 00000000000..1a569113bd2 --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketPresence.tsx @@ -0,0 +1,80 @@ +import React, { useEffect, useState } from 'react' +import { SupabaseClient } from '@supabase/supabase-js' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import solutions from '~/data/Solutions' +import { cn } from 'ui' + +const TicketPresence = (props: { className?: string }) => { + const { supabase, ticketState } = useConfData() + const hasTicket = ticketState === 'ticket' + const [realtimeChannel, setRealtimeChannel] = useState | null>(null) + const [onlineUsers, setOnlineUsers] = useState([]) + const isSingular = onlineUsers.length === 1 + const lowTraffic = onlineUsers.length < 5 + + useEffect(() => { + // Listen to realtime presence + if (!realtimeChannel && supabase) { + const lwxRoom = supabase?.channel('lwx_online', { + config: { broadcast: { self: true, ack: true } }, + }) + + setRealtimeChannel(lwxRoom) + const userStatus = {} + + lwxRoom + ?.on('presence', { event: 'sync' }, () => { + const newState = lwxRoom.presenceState() + const users = [...Object.entries(newState).map(([_, value]) => value[0])] + const uniqueUsrs = users.filter(onlyUnique) + setOnlineUsers(uniqueUsrs) + }) + .subscribe(async (status) => { + if (status !== 'SUBSCRIBED') { + return null + } + await lwxRoom.track(userStatus) + }) + } + + return () => { + realtimeChannel?.unsubscribe() + } + }, []) + + return ( +
    + + {onlineUsers.length} {isSingular ? 'person is' : 'people are'}{' '} + {hasTicket ? 'customizing' : 'generating'} their ticket right now +
    + ) +} + +function onlyUnique(value: any, index: number, array: any[]) { + return array.indexOf(value) === index +} + +export default TicketPresence diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketProfile.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketProfile.tsx new file mode 100644 index 00000000000..4313d9338ad --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketProfile.tsx @@ -0,0 +1,52 @@ +import Image from 'next/image' +import { cn } from 'ui' +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' + +export default function TicketProfile({ className }: { className?: string }) { + const { userData: user } = useConfData() + const { username, name, metadata, platinum, secret: hasSecretTicket } = user + const hasLightTicket = platinum + const profileImg = `https://github.com/${username}.png?size=60` + + const hideAvatar = !!metadata?.hideAvatar + const HAS_ROLE = !!metadata?.role + const HAS_COMPANY = !!metadata?.company + const HAS_NO_META = !HAS_ROLE && !HAS_COMPANY + + return ( +
    +
    + {!hideAvatar && profileImg && ( + + )} +

    {name || username || 'Your Name'}

    + {HAS_NO_META && username && ( +

    + @{username} +

    + )} +
    + {HAS_ROLE && {metadata?.role}} + {HAS_COMPANY && ( + + {HAS_ROLE && at } + {metadata?.company} + + )} +
    +
    +
    + ) +} diff --git a/apps/www/components/LaunchWeek/11/Ticket/TicketingFlow.tsx b/apps/www/components/LaunchWeek/11/Ticket/TicketingFlow.tsx new file mode 100644 index 00000000000..2a2c3d09e5f --- /dev/null +++ b/apps/www/components/LaunchWeek/11/Ticket/TicketingFlow.tsx @@ -0,0 +1,221 @@ +import React from 'react' +import dynamic from 'next/dynamic' +import Image from 'next/image' +import { AnimatePresence, m, LazyMotion, domAnimation } from 'framer-motion' +import { Badge, cn } from 'ui' +import { DEFAULT_TRANSITION, INITIAL_BOTTOM, getAnimation } from '~/lib/animations' +import { LW11_DATE, LW11_LAUNCH_DATE } from '~/lib/constants' +import useWinningChances from '../../hooks/useWinningChances' +import useLwGame from '../../hooks/useLwGame' + +import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' +import SectionContainer from '~/components/Layouts/SectionContainer' +import TicketContainer from '~/components/LaunchWeek/11/Ticket/TicketContainer' +import LW11Background from '../LW11Background' +import TicketForm from './TicketForm' +import CountdownComponent from '../Countdown' +import TicketPresence from './TicketPresence' +import TicketActions from './TicketActions' + +const LWGame = dynamic(() => import('./LW11Game')) + +const TicketingFlow = () => { + const { ticketState, userData, showCustomizationForm } = useConfData() + const { isGameMode, setIsGameMode } = useLwGame(ticketState !== 'ticket' || showCustomizationForm) + + const isLoading = !isGameMode && ticketState === 'loading' + const isRegistering = !isGameMode && ticketState === 'registration' + const hasTicket = !isGameMode && ticketState === 'ticket' + const hasPlatinumTicket = userData.platinum + const hasSecretTicket = userData.secret + const metadata = userData?.metadata + + const transition = DEFAULT_TRANSITION + const initial = INITIAL_BOTTOM + const animate = getAnimation({ duration: 1 }) + const exit = { opacity: 0, transition: { ...transition, duration: 0.2 } } + + const winningChances = useWinningChances() + + return ( + <> + +
    +

    Supabase Special Announcement | {LW11_DATE}

    +
    + + + {isLoading && ( + +
    + +
    + + + +
    + )} + {isRegistering && ( + +
    +

    + Join us for a Special Announcement +

    +

    + Celebrate a major milestone with us and explore all the features that come + with it. +

    +
    +
    +

    {LW11_DATE}

    + +
    + +
    + )} + {hasTicket && ( + +
    + +
    +
    + {hasSecretTicket && Secret ticket} + {hasPlatinumTicket ? ( +
    + {hasSecretTicket && !metadata?.hasSharedSecret ? ( +

    + Share again to boost your chance of winning! +

    + ) : ( +

    Thanks for sharing!

    + )} +

    + Join on April 15-19 to celebrate a major milestone with us and explore + all the features that come with it. +

    +
    + ) : winningChances !== 2 ? ( +
    + {!hasSecretTicket && ( +

    @{userData.username}, you're in!

    + )} +

    + Now share your ticket to have a chance of winning AirPods Max and other + limited swag. +

    +
    + ) : ( +
    +

    @{userData.username}, almost there!

    +

    + Keep sharing to max out your chances of winning AirPods Max and other + limited swag. +

    +
    + )} +
    + +
    +
    + + Starts in: + + +
    +
    +
    + + +
    +
    +

    5 sets

    +

    Win AirPods Max

    +

    + Grow your chances of winning limited edition swag by sharing on{' '} + X and{' '} + Linkedin. +

    +
    +
    + +
    +
    + )} + {!showCustomizationForm && isGameMode && ( + + + + )} +
    +
    +
    +
    +
    + + + ) +} + +export default TicketingFlow diff --git a/apps/www/components/LaunchWeek/11/TicketsGrid.tsx b/apps/www/components/LaunchWeek/11/TicketsGrid.tsx new file mode 100644 index 00000000000..78c5df2204f --- /dev/null +++ b/apps/www/components/LaunchWeek/11/TicketsGrid.tsx @@ -0,0 +1,99 @@ +import { motion } from 'framer-motion' +import Image from 'next/image' +import Link from 'next/link' +import { useBreakpoint } from 'common/hooks/useBreakpoint' +import { UserData } from '../hooks/use-conf-data' + +interface Props { + loadedUsers: UserData[] + isLoading: boolean + pageCount: number + offset: number +} + +export default function TicketsGrid({ loadedUsers, isLoading, pageCount, offset }: Props) { + const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lwx' + const getTicketImageUrl = (username: string, isGold: boolean) => + `${STORAGE_URL}/tickets/${isGold ? 'platinum' : 'regular'}/${username}.png` + const isMobile = useBreakpoint(1024) + const isTablet = useBreakpoint(1280) + const horizontalOffset = isMobile ? 8 : 20 + + return ( +
    + {loadedUsers?.map((user, i) => { + const rowTickets = isMobile ? 2 : isTablet ? 3 : 4 + const divider = Math.floor(i / rowTickets) + const isOddRow = divider % 2 === 0 + // Delay should be no more than pageCount for new loaded users + const recalculatedDelay = i >= pageCount * 2 ? (i - pageCount * (offset - 1)) / 15 : i / 15 + const imgUrl = + getTicketImageUrl(user.username!, !!user.golden) ?? + '/images/launchweek/lwx/tickets/placeholder.png' + + return ( + window.scrollTo(0, 0)} + legacyBehavior + passHref + > + +
    + +
    +
    + + ) + })} + {isLoading && + Array.from({ length: pageCount }, (_, i) => ( + +
    +
    +
    + + ))} +
    + ) +} diff --git a/apps/www/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas.tsx b/apps/www/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas.tsx index c9879188f24..0e258a3bf86 100644 --- a/apps/www/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas.tsx +++ b/apps/www/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas.tsx @@ -17,7 +17,7 @@ const ParticlesCanvas = () => { // to stop unnecessary computations const handleScroll = () => { if (canvasRef.current && typeof window !== 'undefined') { - const rect = (canvasRef.current as HTMLDivElement)?.getBoundingClientRect() + const rect = (canvasRef.current as HTMLCanvasElement)?.getBoundingClientRect() const isInView = rect.bottom > 0 setAnimate(isInView) diff --git a/apps/www/components/LaunchWeek/8/LW8CalloutsSection.tsx b/apps/www/components/LaunchWeek/8/LW8CalloutsSection.tsx index 8158f241ce7..a01589348dc 100644 --- a/apps/www/components/LaunchWeek/8/LW8CalloutsSection.tsx +++ b/apps/www/components/LaunchWeek/8/LW8CalloutsSection.tsx @@ -24,8 +24,9 @@ const LW8CalloutsSection = () => {
    @@ -47,8 +48,9 @@ const LW8CalloutsSection = () => { diff --git a/apps/www/components/LaunchWeek/8/LW8Meetups.tsx b/apps/www/components/LaunchWeek/8/LW8Meetups.tsx index 7ff6e296e76..a2188ecf8c0 100644 --- a/apps/www/components/LaunchWeek/8/LW8Meetups.tsx +++ b/apps/www/components/LaunchWeek/8/LW8Meetups.tsx @@ -61,6 +61,7 @@ const LW8Meetups = ({ meetups }: { meetups?: Meetup[] }) => { ?.sort((a, b) => (new Date(a.start_at) > new Date(b.start_at) ? 1 : -1)) .map(({ display_info, link, isLive, title }: Meetup) => ( { @@ -40,8 +41,9 @@ const LWArchive = () => { diff --git a/apps/www/components/LaunchWeek/8/LaunchWeekPrizeCard.tsx b/apps/www/components/LaunchWeek/8/LaunchWeekPrizeCard.tsx index 98268f1e0c7..1363bc9bc1c 100644 --- a/apps/www/components/LaunchWeek/8/LaunchWeekPrizeCard.tsx +++ b/apps/www/components/LaunchWeek/8/LaunchWeekPrizeCard.tsx @@ -1,6 +1,7 @@ import Image from 'next/image' import React from 'react' import { motion } from 'framer-motion' +import { cn } from 'ui' type animateFromType = 'left' | 'right' | 'up' | 'down' | 'opacityOnly' @@ -56,10 +57,13 @@ export default function LaunchWeekPrizeCard({ > diff --git a/apps/www/components/LaunchWeek/8/LaunchWeekPrizeSection.tsx b/apps/www/components/LaunchWeek/8/LaunchWeekPrizeSection.tsx index a2982bbc9e4..2664fbed640 100644 --- a/apps/www/components/LaunchWeek/8/LaunchWeekPrizeSection.tsx +++ b/apps/www/components/LaunchWeek/8/LaunchWeekPrizeSection.tsx @@ -18,9 +18,9 @@ export default function LaunchWeekPrizeSection({ @@ -32,8 +32,9 @@ export default function LaunchWeekPrizeSection({ @@ -47,7 +48,6 @@ export default function LaunchWeekPrizeSection({ className="col-span-full" imageUrl="/images/launchweek/8/swag/deskmat-lg.jpg" imageWrapperClassName="w-full aspect-[1.9/1] md:h-[300px]" - imgObjectPosition="center" content={

    Supabase Desk Mat diff --git a/apps/www/components/LaunchWeek/8/Releases/components/index.tsx b/apps/www/components/LaunchWeek/8/Releases/components/index.tsx index e9893fb5e7c..a1c0b967c57 100644 --- a/apps/www/components/LaunchWeek/8/Releases/components/index.tsx +++ b/apps/www/components/LaunchWeek/8/Releases/components/index.tsx @@ -85,8 +85,8 @@ export const HackernewsSvg = () => ( export const TwitterSpacesSvg = () => ( @@ -101,8 +101,8 @@ export const ProductHuntSvg = () => ( @@ -118,8 +118,8 @@ export const ProductHuntSvg = () => ( export const CheckCircleSolidIcon = () => ( @@ -259,7 +259,7 @@ export const VideoPreviewTrigger = ({ /> - + {title && {title}} diff --git a/apps/www/components/LaunchWeek/8/Releases/index.tsx b/apps/www/components/LaunchWeek/8/Releases/index.tsx index e90f9c76c6e..7fa6fe08fb9 100644 --- a/apps/www/components/LaunchWeek/8/Releases/index.tsx +++ b/apps/www/components/LaunchWeek/8/Releases/index.tsx @@ -1,6 +1,6 @@ import Image from 'next/image' import Link from 'next/link' -import { Accordion } from 'ui' +import { Accordion, cn } from 'ui' import { useBreakpoint } from 'common/hooks/useBreakpoint' import { @@ -77,7 +77,10 @@ export default function LW8Releases() { preRelease.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -121,7 +123,10 @@ export default function LW8Releases() { preRelease.steps[1]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -163,18 +167,25 @@ export default function LW8Releases() { preRelease.steps[2]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -222,18 +233,23 @@ export default function LW8Releases() { day1.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -280,17 +296,20 @@ export default function LW8Releases() { day2.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -351,15 +370,21 @@ export default function LW8Releases() { day3.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -406,15 +431,21 @@ export default function LW8Releases() { day4.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -444,14 +475,17 @@ export default function LW8Releases() { day4.steps[1]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -498,14 +532,17 @@ export default function LW8Releases() { day5.steps[0]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -536,14 +573,17 @@ export default function LW8Releases() { day5.steps[1]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    @@ -574,15 +614,20 @@ export default function LW8Releases() { day5.steps[2]?.bg_layers?.map( (layer, i) => !!layer.img && ( -
    +
    diff --git a/apps/www/components/LaunchWeek/8/TicketBrickWallSlider.tsx b/apps/www/components/LaunchWeek/8/TicketBrickWallSlider.tsx index 589a06da539..e4d97229aef 100644 --- a/apps/www/components/LaunchWeek/8/TicketBrickWallSlider.tsx +++ b/apps/www/components/LaunchWeek/8/TicketBrickWallSlider.tsx @@ -5,6 +5,7 @@ import { UserData } from '~/components/LaunchWeek/hooks/use-conf-data' import { Swiper, SwiperSlide } from 'swiper/react' import 'swiper/swiper.min.css' +import { cn } from 'ui' interface Props { users: UserData[] @@ -24,10 +25,10 @@ export function TicketBrickWallSlider({ users, reverse, speed = 50000, animate } return (
    diff --git a/apps/www/components/LaunchWeek/X/FaviconImports.tsx b/apps/www/components/LaunchWeek/X/FaviconImports.tsx new file mode 100644 index 00000000000..cb681a9de46 --- /dev/null +++ b/apps/www/components/LaunchWeek/X/FaviconImports.tsx @@ -0,0 +1,93 @@ +import Head from 'next/head' +import { useRouter } from 'next/router' + +function FaviconImports() { + const { basePath } = useRouter() + + return ( + + + + + + + + + + + + + + + + + + + + + ) +} + +export default FaviconImports diff --git a/apps/www/components/LaunchWeek/X/LaunchWeekPrizeSection.tsx b/apps/www/components/LaunchWeek/X/LaunchWeekPrizeSection.tsx index 10011ab5e07..f5c9a1e66c1 100644 --- a/apps/www/components/LaunchWeek/X/LaunchWeekPrizeSection.tsx +++ b/apps/www/components/LaunchWeek/X/LaunchWeekPrizeSection.tsx @@ -14,7 +14,6 @@ export default function LaunchWeekPrizeSection({ className }: { className?: stri )} >

    Awards

    -

    Stay tuned on Launch Week X's final day to find out if you're one of the lucky winners.

    {
    - Launch Week{' '} - + + Launch Week + {' '} + + +
    {/* Nav items */} diff --git a/apps/www/components/LaunchWeek/X/Releases/MainStage.tsx b/apps/www/components/LaunchWeek/X/Releases/MainStage.tsx index 237baf8e915..55a393fd604 100644 --- a/apps/www/components/LaunchWeek/X/Releases/MainStage.tsx +++ b/apps/www/components/LaunchWeek/X/Releases/MainStage.tsx @@ -12,11 +12,11 @@ const MainStage: FC = () => (

    - Hackathon concluded + Hackathon finished
    - - - - - ), - id: 'supabase-album', - is_shipped: true, - links: [ - { - url: 'https://supabase.productions/', - label: 'Listen now', - target: '_blank', - }, - ], - }, - { - title: 'Postgres Language Server', - description: 'Implementing the Parser', + title: 'TBD', + description: '', icon: ( ), - id: 'postgres-language-server-implementing-parser', + id: '', is_shipped: true, links: [ { - url: '/blog/postgres-language-server-implementing-parser', + url: '#', label: 'Read blog post', - }, - ], - }, - { - title: 'Design at Supabase', - description: "The transformative journey of Supabase's Design team", - icon: ( - - - - - ), - id: 'design-at-supabase', - is_shipped: true, - links: [ - { - url: '/blog/how-design-works-at-supabase', - label: 'Read blog post', - }, - ], - }, - { - title: 'Supabase Grafana', - description: 'Observability for your Supabase project', - is_shipped: true, - icon: ( - - - - ), - id: 'supabase-grafana', - links: [ - { - url: 'https://github.com/supabase/supabase-grafana', - label: 'View on GitHub', target: '_blank', }, ], }, { - title: 'pg_graphql: Postgres functions', - description: 'pg_graphql now supports User Defined Functions (UDFs)', - is_shipped: true, + title: 'TBD', + description: '', icon: ( + ), - id: 'pg-graphql-postgres-functions', + id: '', + is_shipped: true, links: [ { - url: '/blog/pg-graphql-postgres-functions', + url: '#', label: 'Read blog post', + target: '_blank', }, ], }, { - title: 'PostgREST 12', - description: 'PostgREST 12 is out: take a look at some of the major new features', - is_shipped: true, - className: 'xl:col-span-2 xl:h-auto xl:aspect-auto', + title: 'TBD', + description: '', icon: ( - - - - ), - id: 'postgrest-12', - links: [ - { - url: '/blog/postgrest-12', - label: 'Read blog post', - }, - ], - }, - { - title: 'Supavisor 1.0', - description: 'A scalable connection pooler for Postgres', - is_shipped: true, - icon: ( - + ), - id: 'supavisor', + id: '', + is_shipped: true, links: [ { - url: '/blog/supavisor-postgres-connection-pooler', + url: '#', label: 'Read blog post', + target: '_blank', }, ], }, { - title: 'Supabase Wrappers v0.2', - description: 'Query Pushdown & Remote Subqueries', - is_shipped: true, + title: 'TBD', + description: '', icon: ( + ), - id: 'supabase-wrappers-v0.2', + id: '', + is_shipped: true, links: [ { - url: '/blog/supabase-wrappers-v02', + url: '#', label: 'Read blog post', + target: '_blank', }, ], }, { - title: 'Supabase Libraries V2', - description: 'Swift, Kotlin, C#, and Python are now stable and moving to the v2 API', - type: 'clientLibs', - is_shipped: true, - className: 'xl:col-span-2 xl:aspect-auto xl:col-span-3 xl:aspect-auto xl:h-full', - id: 'supabase-libraries-v2', - links: [ - { - url: '/blog/client-libraries-v2', - label: 'Read blog post', - }, - ], - icons: [ - { - url: '/blog/client-libraries-v2#supabase-python-v2', - label: 'Python', - icon: ( - - - - - ), - }, - { - url: '/blog/client-libraries-v2#supabase-swift-v2', - label: 'Swift', - icon: ( - - - - ), - }, - { - url: '/blog/client-libraries-v2#supabase-kotlin-v2', - label: 'Kotlin', - icon: ( - - - - ), - }, - { - url: '/blog/client-libraries-v2#typescript-v2-updates', - label: 'Typescript', - icon: ( - - - - ), - }, - { - url: '/blog/client-libraries-v2#flutter-v2-updates', - label: 'Flutter', - icon: ( - - - - - ), - }, - ], - }, - { - title: 'Supabase x Fly.io', - description: - "We're launching a managed Postgres offering jointly developed by Supabase and Fly.io", - is_shipped: true, - className: 'xl:col-span-2 xl:aspect-auto h-full', + title: 'TBD', + description: '', icon: ( - - - - + ), - id: 'fly-postgres', + id: '', + is_shipped: true, links: [ { - url: '/blog/postgres-on-fly-by-supabase', + url: '#', label: 'Read blog post', + target: '_blank', }, ], }, { - title: 'Top 10 Launches of LWX', - description: 'Our CEO takes a look at his favorite ships from LWX', - className: 'sm:aspect-[2/1] sm:col-span-1 sm:col-span-2 sm:aspect-[2/1] h-full', - is_shipped: true, + title: 'TBD', + description: '', icon: ( - + ), - id: 'launch-week-x-best-launches', + id: '', + is_shipped: true, links: [ { - url: '/blog/launch-week-x-best-launches', + url: '#', label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', + }, + ], + }, + { + title: 'TBD', + description: '', + icon: ( + + + + + ), + id: '', + is_shipped: true, + links: [ + { + url: '#', + label: 'Read blog post', + target: '_blank', }, ], }, diff --git a/apps/www/components/LaunchWeek/X/Ticket/LWXGame.tsx b/apps/www/components/LaunchWeek/X/Ticket/LWXGame.tsx index cb63914006e..9e4c6ed6131 100644 --- a/apps/www/components/LaunchWeek/X/Ticket/LWXGame.tsx +++ b/apps/www/components/LaunchWeek/X/Ticket/LWXGame.tsx @@ -2,7 +2,7 @@ import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' import { Button, cn } from 'ui' import { SITE_ORIGIN } from '~/lib/constants' import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' -import { VALID_KEYS } from '~/components/LaunchWeek/hooks/useLwxGame' +import { VALID_KEYS } from '~/components/LaunchWeek/hooks/useLwGame' const COMPLIMENTS = [ 'Congratulations!', diff --git a/apps/www/components/LaunchWeek/X/Ticket/TicketContainer.tsx b/apps/www/components/LaunchWeek/X/Ticket/TicketContainer.tsx index c7491598dc7..20dad57faa3 100644 --- a/apps/www/components/LaunchWeek/X/Ticket/TicketContainer.tsx +++ b/apps/www/components/LaunchWeek/X/Ticket/TicketContainer.tsx @@ -1,7 +1,5 @@ -import useConfData from '~/components/LaunchWeek/hooks/use-conf-data' import { useParams } from 'common' import Ticket from './Ticket' -import TicketActions from './TicketActions' import TicketCustomizationForm from './TicketCustomizationForm' import TicketCopy from './TicketCopy' diff --git a/apps/www/components/LaunchWeek/X/Ticket/TicketCopy.tsx b/apps/www/components/LaunchWeek/X/Ticket/TicketCopy.tsx index 9e53f2050a8..d44b811ce33 100644 --- a/apps/www/components/LaunchWeek/X/Ticket/TicketCopy.tsx +++ b/apps/www/components/LaunchWeek/X/Ticket/TicketCopy.tsx @@ -6,11 +6,11 @@ import { IconCheck, IconCopy, cn } from 'ui' export default function TicketCopy({ sharePage }: { sharePage: boolean }) { const { userData } = useConfData() const { username, golden, metadata } = userData - const [copyEnabled, setCopyEnabled] = useState(false) + const [_copyEnabled, setCopyEnabled] = useState(false) const [copied, setCopied] = useState(false) const buttonRef = useRef(null) const hasSecretTicket = metadata?.hasSecretTicket - const url = `${SITE_URL}/tickets/${username}?lw=x${ + const url = `${SITE_URL}/x/tickets/${username}?lw=x${ hasSecretTicket ? '&secret=true' : golden ? `&platinum=true` : '' }` diff --git a/apps/www/components/LaunchWeek/X/Ticket/TicketingFlow.tsx b/apps/www/components/LaunchWeek/X/Ticket/TicketingFlow.tsx index 47ccfdda752..959a6c7204f 100644 --- a/apps/www/components/LaunchWeek/X/Ticket/TicketingFlow.tsx +++ b/apps/www/components/LaunchWeek/X/Ticket/TicketingFlow.tsx @@ -16,7 +16,7 @@ import CountdownComponent from '../Countdown' import LaunchWeekPrizeSection from '../LaunchWeekPrizeSection' import TicketPresence from './TicketPresence' import TicketActions from './TicketActions' -import useLwxGame from '../../hooks/useLwxGame' +import useLwxGame from '../../hooks/useLwGame' import LWXGame from './LWXGame' const TicketingFlow = () => { diff --git a/apps/www/components/LaunchWeek/X/TicketsGrid.tsx b/apps/www/components/LaunchWeek/X/TicketsGrid.tsx index 614720c7743..ffea3c5bbb0 100644 --- a/apps/www/components/LaunchWeek/X/TicketsGrid.tsx +++ b/apps/www/components/LaunchWeek/X/TicketsGrid.tsx @@ -35,7 +35,7 @@ export default function TicketsGrid({ loadedUsers, isLoading, pageCount, offset return ( window.scrollTo(0, 0)} legacyBehavior @@ -63,9 +63,9 @@ export default function TicketsGrid({ loadedUsers, isLoading, pageCount, offset diff --git a/apps/www/components/LaunchWeek/hooks/use-conf-data.ts b/apps/www/components/LaunchWeek/hooks/use-conf-data.ts index 1f348a0aa3f..397a49262b0 100644 --- a/apps/www/components/LaunchWeek/hooks/use-conf-data.ts +++ b/apps/www/components/LaunchWeek/hooks/use-conf-data.ts @@ -9,6 +9,7 @@ export type UserData = { ticketNumber?: number username?: string name?: string + platinum?: boolean golden?: boolean referrals?: number bg_image_id?: number @@ -17,9 +18,12 @@ export type UserData = { company?: string location?: string hasSecretTicket?: boolean + hasSharedSecret?: boolean + hideAvatar?: boolean } sharedOnTwitter?: string sharedOnLinkedIn?: string + secret?: boolean } type ConfDataContextType = { diff --git a/apps/www/components/LaunchWeek/hooks/useLwxGame.tsx b/apps/www/components/LaunchWeek/hooks/useLwGame.tsx similarity index 74% rename from apps/www/components/LaunchWeek/hooks/useLwxGame.tsx rename to apps/www/components/LaunchWeek/hooks/useLwGame.tsx index bc4c4e63f2a..f5fe1403267 100644 --- a/apps/www/components/LaunchWeek/hooks/useLwxGame.tsx +++ b/apps/www/components/LaunchWeek/hooks/useLwGame.tsx @@ -30,12 +30,11 @@ export const VALID_KEYS = [ 'z', ] -const useLwxGame = (showCustomizationForm?: boolean) => { +const useLwGame = (disabled?: boolean) => { const [isGameMode, setIsGameMode] = useState(false) - const { ticketState } = useConfData() function onKeyDown(event: KeyboardEvent) { - if (showCustomizationForm) return + if (disabled) return if (event.key === 'Escape') { setIsGameMode(false) @@ -49,12 +48,12 @@ const useLwxGame = (showCustomizationForm?: boolean) => { } useEffect(() => { - if (!showCustomizationForm) window.addEventListener('keydown', onKeyDown) + if (!disabled) window.addEventListener('keydown', onKeyDown) return () => window.removeEventListener('keydown', onKeyDown) - }, [showCustomizationForm]) + }, [disabled]) return { isGameMode, setIsGameMode } } -export default useLwxGame +export default useLwGame diff --git a/apps/www/components/Nav/index.tsx b/apps/www/components/Nav/index.tsx index d8d1ca6f1bf..a6253772638 100644 --- a/apps/www/components/Nav/index.tsx +++ b/apps/www/components/Nav/index.tsx @@ -5,7 +5,7 @@ import { useRouter } from 'next/router' import { useTheme } from 'next-themes' import { useWindowSize } from 'react-use' -import { Button, cn } from 'ui' +import { Announcement, Button, cn, LW11CountdownBanner } from 'ui' import { NavigationMenu, NavigationMenuContent, @@ -38,8 +38,10 @@ const Nav = (props: Props) => { const isUserLoading = useIsUserLoading() const isHomePage = router.pathname === '/' - const isLaunchWeekPage = router.pathname.includes('launch-week') - const isLaunchWeekXPage = router.pathname === '/launch-week' + const isSpecialAnnouncementPage = router.pathname.includes('special-announcement') + const isLaunchWeekPage = router.pathname.includes('launch-week') || isSpecialAnnouncementPage + const isLaunchWeekXPage = router.pathname === '/launch-week/x' + const isLaunchWeek11Page = router.pathname === '/special-announcement' const showLaunchWeekNavMode = isLaunchWeekPage && !open React.useEffect(() => { @@ -64,6 +66,9 @@ const Nav = (props: Props) => { return ( <> + + +
    { /> - {isLaunchWeekPage && !isLaunchWeekXPage && ( - - Launch Week - - )} + {!isSpecialAnnouncementPage && + !isLaunchWeek11Page && + isLaunchWeekPage && + !isLaunchWeekXPage && ( + + Launch Week + + )}
    ) => { const outerRef = useRef(null) const innerRef = useRef(null) @@ -85,6 +87,7 @@ const Panel = ({ outerClassName )} {...(hasMotion ? { whileHover: 'hover', animate: 'initial' } : undefined)} + style={style} >
    ] + +export type Tables< + PublicTableNameOrOptions extends + | keyof (PublicSchema['Tables'] & PublicSchema['Views']) + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views']) + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { + Row: infer R + } + ? R + : never + : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & PublicSchema['Views']) + ? (PublicSchema['Tables'] & PublicSchema['Views'])[PublicTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + PublicTableNameOrOptions extends keyof PublicSchema['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Insert: infer I + } + ? I + : never + : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] + ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + PublicTableNameOrOptions extends keyof PublicSchema['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Update: infer U + } + ? U + : never + : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] + ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + : never = never, +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] + ? PublicSchema['Enums'][PublicEnumNameOrOptions] + : never diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js index f05641e3d90..d1f9cf48575 100644 --- a/apps/www/lib/redirects.js +++ b/apps/www/lib/redirects.js @@ -2401,11 +2401,21 @@ module.exports = [ { permanent: true, source: '/docs/guides/auth/sso/auth-sso-saml', - destination: '/guides/auth/enterprise-sso/auth-sso-saml', + destination: '/docs/guides/auth/enterprise-sso/auth-sso-saml', }, { permanent: true, source: '/contact/mfa', destination: '/docs/guides/auth/auth-mfa', }, + { + permanent: false, + source: '/launch-week', + destination: '/special-announcement', + }, + { + permanent: false, + source: '/launch-week/tickets/:path*', + destination: '/special-announcement/tickets/:path*', + }, ] diff --git a/apps/www/lib/supabaseMiscAdmin.ts b/apps/www/lib/supabaseMiscAdmin.ts new file mode 100644 index 00000000000..2a9791fed85 --- /dev/null +++ b/apps/www/lib/supabaseMiscAdmin.ts @@ -0,0 +1,11 @@ +import { createClient } from '@supabase/supabase-js' +import { Database } from './database.types' + +const supabaseMiscAdmin = createClient( + process.env.NEXT_PUBLIC_MISC_USE_URL!, + process.env.MISC_USE_SERVICE_ROLE_KEY! +) + +export type SupabaseClient = typeof supabaseMiscAdmin + +export default supabaseMiscAdmin diff --git a/apps/www/package.json b/apps/www/package.json index e6896ddd9a5..0a6ee2c91d9 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -16,8 +16,8 @@ "@code-hike/mdx": "^0.9.0", "@heroicons/react": "^1.0.6", "@mdx-js/react": "^2.3.0", - "@next/bundle-analyzer": "^13.5.6", - "@next/mdx": "^13.5.6", + "@next/bundle-analyzer": "^14.1.4", + "@next/mdx": "^14.1.4", "@octokit/auth-app": "^6.0.3", "@octokit/core": "^5.0.2", "@octokit/graphql": "^7.0.2", @@ -26,7 +26,8 @@ "@react-three/fiber": "^7.0.29", "@supabase/auth-helpers-react": "^0.4.2", "@supabase/auth-ui-react": "^0.4.5", - "@supabase/supabase-js": "^2.39.3", + "animejs": "^3.2.2", + "@supabase/supabase-js": "^2.41.1", "classnames": "^2.3.1", "cobe": "^0.6.2", "common": "*", @@ -38,10 +39,10 @@ "gray-matter": "^4.0.3", "icons": "*", "markdown-toc": "^1.2.0", - "next": "^13.4.8", + "next": "^14.1.4", "next-mdx-remote": "^4.4.1", "next-seo": "^6.5.0", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "parse-numeric-range": "^1.3.0", "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", @@ -70,6 +71,7 @@ "yup": "^1.4.0" }, "devDependencies": { + "@types/animejs": "^3.1.12", "@types/classnames": "^2.3.1", "@types/dat.gui": "^0.7.10", "@types/mdx-js__react": "^1.5.6", diff --git a/apps/www/pages/_app.tsx b/apps/www/pages/_app.tsx index 6a3cf659dcc..9e5ed2334de 100644 --- a/apps/www/pages/_app.tsx +++ b/apps/www/pages/_app.tsx @@ -67,15 +67,17 @@ export default function App({ Component, pageProps }: AppProps) { const site_title = `${APP_NAME} | The Open Source Firebase Alternative` const { basePath, pathname } = useRouter() - const forceDarkMode = pathname === '/' || router.pathname.startsWith('/launch-week') + const isSpecialAnnouncementPage = router.pathname.startsWith('/special-announcement') + const forceDarkMode = + pathname === '/' || router.pathname.startsWith('/launch-week') || isSpecialAnnouncementPage let applicationName = 'Supabase' let faviconRoute = DEFAULT_FAVICON_ROUTE let themeColor = DEFAULT_FAVICON_THEME_COLOR - if (router.asPath && router.asPath.includes('/launch-week')) { + if (router.asPath && router.asPath.includes('/launch-week/x')) { applicationName = 'Supabase LWX' - faviconRoute = 'images/launchweek/lwx/favicon/' + faviconRoute = 'images/launchweek/lwx/favicon' themeColor = 'FFFFFF' } diff --git a/apps/www/pages/launch-week/6/index.tsx b/apps/www/pages/launch-week/6/index.tsx index 2ee0b96a45b..55ff23a0fe0 100644 --- a/apps/www/pages/launch-week/6/index.tsx +++ b/apps/www/pages/launch-week/6/index.tsx @@ -247,12 +247,7 @@ export default function launchweek() {
    - +
    Wrap Up @@ -982,7 +977,7 @@ export default function launchweek() { + />

    Super UI

    Previous Best Overall Project Runner Up

    @@ -1071,24 +1066,21 @@ export default function launchweek() { })}
    - + Shipped

    The Supabase Content Storm

    We worked with more than 30 content creators from around the world to drop a mountain of content simultaneously! - -

    + + See all the content +

    {activeCreator !== null && ( diff --git a/apps/www/pages/launch-week/8/index.tsx b/apps/www/pages/launch-week/8/index.tsx index a0c1364e38a..e054c7c8ab0 100644 --- a/apps/www/pages/launch-week/8/index.tsx +++ b/apps/www/pages/launch-week/8/index.tsx @@ -1,3 +1,5 @@ +import 'swiper/swiper.min.css' + import { useState, useEffect } from 'react' import { GetServerSideProps } from 'next' import dynamic from 'next/dynamic' @@ -14,12 +16,8 @@ import SectionContainer from '~/components/Layouts/SectionContainer' import { LaunchWeekLogoHeader } from '~/components/LaunchWeek/8/LaunchWeekLogoHeader' import { Meetup } from '~/components/LaunchWeek/8/LW8Meetups' import LW8CalloutsSection from '~/components/LaunchWeek/8/LW8CalloutsSection' +import AnimatedParticles from '~/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas' -import 'swiper/swiper.min.css' - -const AnimatedParticles = dynamic( - () => import('~/components/LaunchWeek/8/AnimatedParticles/ParticlesCanvas') -) const LW8Releases = dynamic(() => import('~/components/LaunchWeek/8/Releases')) const LW8Meetups = dynamic(() => import('~/components/LaunchWeek/8/LW8Meetups')) const LWArchive = dynamic(() => import('~/components/LaunchWeek/8/LWArchive')) @@ -145,7 +143,9 @@ export default function TicketHome({ users, meetups }: Props) {
    diff --git a/apps/www/pages/launch-week/index.tsx b/apps/www/pages/launch-week/x/index.tsx similarity index 97% rename from apps/www/pages/launch-week/index.tsx rename to apps/www/pages/launch-week/x/index.tsx index 7b101763c80..9507c9c411d 100644 --- a/apps/www/pages/launch-week/index.tsx +++ b/apps/www/pages/launch-week/x/index.tsx @@ -7,6 +7,7 @@ import { Session } from '@supabase/supabase-js' import { SITE_ORIGIN, SITE_URL } from '~/lib/constants' import supabase from '~/lib/supabaseMisc' +import FaviconImports from '~/components/LaunchWeek/X/FaviconImports' import DefaultLayout from '~/components/Layouts/Default' import { TicketState, ConfDataContext, UserData } from '~/components/LaunchWeek/hooks/use-conf-data' import SectionContainer from '~/components/Layouts/SectionContainer' @@ -98,6 +99,7 @@ export default function LaunchWeekIndex({ meetups }: Props) { ], }} /> + { return { props: { + // @ts-ignore meetups: meetups?.sort((a, b) => (new Date(a.start_at) > new Date(b.start_at) ? 1 : -1)), }, } diff --git a/apps/www/pages/launch-week/tickets/[username].tsx b/apps/www/pages/launch-week/x/tickets/[username].tsx similarity index 92% rename from apps/www/pages/launch-week/tickets/[username].tsx rename to apps/www/pages/launch-week/x/tickets/[username].tsx index 0dba55e2316..9e6d81d6b55 100644 --- a/apps/www/pages/launch-week/tickets/[username].tsx +++ b/apps/www/pages/launch-week/x/tickets/[username].tsx @@ -10,6 +10,7 @@ import { Button } from 'ui' import { SITE_URL } from '~/lib/constants' import supabase from '~/lib/supabaseMisc' +import FaviconImports from '~/components/LaunchWeek/X/FaviconImports' import DefaultLayout from '~/components/Layouts/Default' import SectionContainer from '~/components/Layouts/SectionContainer' import { TicketState, ConfDataContext, UserData } from '~/components/LaunchWeek/hooks/use-conf-data' @@ -32,7 +33,7 @@ export default function UsernamePage({ user, ogImageUrl }: Props) { const TITLE = `${name ? name + '’s' : 'Get your'} #SupaLaunchWeek Ticket` const DESCRIPTION = `Claim and share your Supabase Launch Week X ticket for a chance to win Supabase swag.` - const OG_URL = `${SITE_URL}/tickets/${username}` + const OG_URL = `${SITE_URL}/x/tickets/${username}` const [session, setSession] = useState(null) const { resolvedTheme, setTheme } = useTheme() @@ -71,7 +72,7 @@ export default function UsernamePage({ user, ogImageUrl }: Props) { ], }} /> - + Launch Week X Ticket - - Claim your own ticket and share it for a chance to win. -
    @@ -142,6 +138,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { user = data } + // @ts-ignore const ticketType = user?.metadata?.hasSecretTicket ? 'secret' : user?.golden @@ -159,7 +156,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { ogImageUrl, key: username, }, - revalidate: 5, + // revalidate: 5, } } diff --git a/apps/www/pages/launch-week/tickets/index.tsx b/apps/www/pages/launch-week/x/tickets/index.tsx similarity index 97% rename from apps/www/pages/launch-week/tickets/index.tsx rename to apps/www/pages/launch-week/x/tickets/index.tsx index 93a215c1338..6bb8e7d0a81 100644 --- a/apps/www/pages/launch-week/tickets/index.tsx +++ b/apps/www/pages/launch-week/x/tickets/index.tsx @@ -14,7 +14,7 @@ import SectionContainer from '~/components/Layouts/SectionContainer' import { UserData } from '~/components/LaunchWeek/hooks/use-conf-data' import CTABanner from '~/components/CTABanner' import TicketsGrid from '~/components/LaunchWeek/X/TicketsGrid' -import supabase from '../../../lib/supabaseMisc' +import supabase from '~/lib/supabaseMisc' interface Props { users: UserData[] @@ -127,7 +127,7 @@ export default function TicketsPage({ users }: Props) {

    diff --git a/apps/www/pages/partners/integrations/[slug].tsx b/apps/www/pages/partners/integrations/[slug].tsx index 171bad34821..ac3e6c3ec1f 100644 --- a/apps/www/pages/partners/integrations/[slug].tsx +++ b/apps/www/pages/partners/integrations/[slug].tsx @@ -1,24 +1,28 @@ -import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' +import { type CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' import { CH } from '@code-hike/mdx/components' -import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } -import { GetStaticPaths, GetStaticProps } from 'next' -import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote' -import { serialize } from 'next-mdx-remote/serialize' -import { NextSeo } from 'next-seo' +import { ChevronLeft, ExternalLink } from 'lucide-react' +import { type GetStaticPaths, type GetStaticProps } from 'next' import Image from 'next/image' import Link from 'next/link' -import { Dispatch, SetStateAction, useState } from 'react' +import { MDXRemote, type MDXRemoteSerializeResult } from 'next-mdx-remote' +import { serialize } from 'next-mdx-remote/serialize' +import { NextSeo } from 'next-seo' +import { type Dispatch, type SetStateAction, useState } from 'react' import remarkGfm from 'remark-gfm' import { Swiper, SwiperSlide } from 'swiper/react' import 'swiper/swiper.min.css' -import { Admonition, Button, IconChevronLeft, IconExternalLink } from 'ui' + +import { useBreakpoint } from 'common' +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } +import { Admonition, Button } from 'ui' +import { ExpandableVideo } from 'ui-patterns/ExpandableVideo' + import ImageModal from '~/components/ImageModal' import DefaultLayout from '~/components/Layouts/Default' import SectionContainer from '~/components/Layouts/SectionContainer' import supabase from '~/lib/supabaseMisc' import type { Partner } from '~/types/partners' import Error404 from '../../404' -import { ExpandableVideo } from 'ui-patterns/ExpandableVideo' /** * Returns custom components so that the markdown converts to a nice looking html. @@ -48,13 +52,10 @@ function Partner({ overview: MDXRemoteSerializeResult, Record> }) { const [focusedImage, setFocusedImage] = useState(null) + const isNarrow = useBreakpoint('lg') if (!partner) return - const videoThumbnail = partner.video - ? `http://img.youtube.com/vi/${partner.video}/0.jpg` - : undefined - return ( <> - + Back @@ -174,7 +175,9 @@ function Partner({
    -
    +
    + {isNarrow && } +

    -
    -
    -

    - Details -

    - - {partner.video && ( -
    - -
    - )} - -
    - {partner.type === 'technology' && ( -
    - Developer - {partner.developer} -
    - )} - -
    - Category - - {partner.category} - -
    - - - - {partner.type === 'technology' && partner.docs && ( -
    - Documentation - - - Learn - - - -
    - )} -
    -
    -
    + {!isNarrow && }
    {partner.call_to_action_link && (
    @@ -279,6 +214,84 @@ function Partner({ ) } +const PartnerDetails = ({ partner }: { partner: Partner }) => { + const videoThumbnail = partner.video + ? `http://img.youtube.com/vi/${partner.video}/0.jpg` + : undefined + + return ( +
    +
    +

    + Details +

    + + {partner.video && ( +
    + +
    + )} + +
    + {partner.type === 'technology' && ( +
    + Developer + {partner.developer} +
    + )} + +
    + Category + + {partner.category} + +
    + + + + {partner.type === 'technology' && partner.docs && ( +
    + Documentation + + + Learn + + + +
    + )} +
    +

    + Third-party integrations and docs are managed by Supabase partners. +

    +
    +
    + ) +} + // This function gets called at build time export const getStaticPaths: GetStaticPaths = async () => { const { data: slugs } = await supabase diff --git a/apps/www/pages/special-announcement/index.tsx b/apps/www/pages/special-announcement/index.tsx new file mode 100644 index 00000000000..1cf42e3b82a --- /dev/null +++ b/apps/www/pages/special-announcement/index.tsx @@ -0,0 +1,103 @@ +import { useState, useEffect } from 'react' +import { useRouter } from 'next/router' +import { NextSeo } from 'next-seo' +import { Session } from '@supabase/supabase-js' +import { SITE_ORIGIN, SPECIAL_ANNOUNCEMENT_URL } from '~/lib/constants' +import supabase from '~/lib/supabaseMisc' + +import DefaultLayout from '~/components/Layouts/Default' +import { TicketState, ConfDataContext, UserData } from '~/components/LaunchWeek/hooks/use-conf-data' +import TicketingFlow from '~/components/LaunchWeek/11/Ticket/TicketingFlow' + +export default function LaunchWeekIndex() { + const { query } = useRouter() + + const TITLE = 'Supabase Special Announcement | 15-19 April' + const DESCRIPTION = 'Join us for a week of announcing new features, every day at 7 AM PT.' + const OG_IMAGE = `${SITE_ORIGIN}/images/launchweek/11/lw11-og.png` + + const ticketNumber = query.ticketNumber?.toString() + const bgImageId = query.bgImageId?.toString() + const [session, setSession] = useState(null) + const [showCustomizationForm, setShowCustomizationForm] = useState(false) + + const defaultUserData = { + id: query.id?.toString(), + ticketNumber: ticketNumber ? parseInt(ticketNumber, 10) : undefined, + name: query.name?.toString(), + username: query.username?.toString(), + golden: !!query.golden, + bgImageId: bgImageId ? parseInt(bgImageId, 10) : undefined, + } + + const [userData, setUserData] = useState(defaultUserData) + const [ticketState, setTicketState] = useState('loading') + + useEffect(() => { + if (supabase) { + supabase.auth.getSession().then(({ data: { session } }) => setSession(session)) + const { + data: { subscription }, + } = supabase.auth.onAuthStateChange((_event, session) => { + setSession(session) + }) + + return () => subscription.unsubscribe() + } + }, [supabase]) + + useEffect(() => { + document.body.classList.add('bg-[#060809]') + + return () => { + if (document.body.classList.contains('bg-[#060809]')) { + document.body.classList.remove('bg-[#060809]') + } + } + }, []) + + useEffect(() => { + if (session?.user) { + if (userData?.id) { + return setTicketState('ticket') + } + return setTicketState('loading') + } + if (!session) return setTicketState('registration') + }, [session, userData]) + + return ( + <> + + + + + + + + ) +} diff --git a/apps/www/pages/special-announcement/tickets/[username].tsx b/apps/www/pages/special-announcement/tickets/[username].tsx new file mode 100644 index 00000000000..d541a679b29 --- /dev/null +++ b/apps/www/pages/special-announcement/tickets/[username].tsx @@ -0,0 +1,159 @@ +import { useEffect, useState } from 'react' +import { NextSeo } from 'next-seo' +import { GetStaticProps, GetStaticPaths } from 'next' +import Link from 'next/link' +import Error from 'next/error' +import dynamic from 'next/dynamic' +import { Session } from '@supabase/supabase-js' +import { Button } from 'ui' +import { SITE_URL, SPECIAL_ANNOUNCEMENT_URL } from '~/lib/constants' +import supabase from '~/lib/supabaseMisc' +import supabaseMiscAdmin from '~/lib/supabaseMiscAdmin' +import dayjs from 'dayjs' + +import DefaultLayout from '~/components/Layouts/Default' +import SectionContainer from '~/components/Layouts/SectionContainer' +import { TicketState, ConfDataContext, UserData } from '~/components/LaunchWeek/hooks/use-conf-data' +import LW11Background from '~/components/LaunchWeek/11/LW11Background' + +const LW11TicketContainer = dynamic( + () => import('~/components/LaunchWeek/11/Ticket/TicketContainer') +) +const LaunchWeekPrizeSection = dynamic( + () => import('~/components/LaunchWeek/11/LaunchWeekPrizeSection') +) +const CTABanner = dynamic(() => import('~/components/CTABanner')) + +interface Props { + user: UserData + users: UserData[] + ogImageUrl: string +} + +export default function UsernamePage({ user, ogImageUrl }: Props) { + const { username, ticketNumber, name } = user + + const DISPLAY_NAME = name || username + const TITLE = `${DISPLAY_NAME ? DISPLAY_NAME.split(' ')[0] + '’s' : 'Get your'} ticket` + const DESCRIPTION = `` + const PAGE_URL = `${SPECIAL_ANNOUNCEMENT_URL}/tickets/${username}` + + const [session] = useState(null) + + const [ticketState, setTicketState] = useState('ticket') + + if (!ticketNumber) { + return + } + + useEffect(() => { + document.body.classList.add('bg-[#060809]') + + return () => { + if (document.body.classList.contains('bg-[#060809]')) { + document.body.classList.remove('bg-[#060809]') + } + } + }, []) + + return ( + <> + + null, + ticketState, + setTicketState, + }} + > + +
    + +
    + +
    +
    +

    {DISPLAY_NAME?.split(' ')[0]}'s Ticket

    + + Join @{username} for a Special Announcement and create your ticket for a chance to + win swag. + + +
    +
    + +
    + + + + +
    +
    + + ) +} + +export const getStaticProps: GetStaticProps = async ({ params }) => { + const username = params?.username?.toString() || null + let user + + fetch( + `https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw11-og?username=${encodeURIComponent( + username ?? '' + )}` + ) + + // fetch a specific user + if (username) { + const { data } = await supabaseMiscAdmin! + .from('lw11_tickets_platinum') + .select('name, username, ticketNumber, metadata, platinum, secret') + .eq('username', username) + .single() + + user = data + } + + const ticketType = user?.secret ? 'secret' : user?.platinum ? 'platinum' : 'regular' + const ogImageUrl = `https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw11/og/${ticketType}/${username}.png?t=${dayjs(new Date()).format('DHHmmss')}` + + return { + props: { + user: { + ...user, + username, + }, + ogImageUrl, + key: username, + }, + revalidate: 5, + } +} + +export const getStaticPaths: GetStaticPaths = async () => { + return Promise.resolve({ + paths: [], + fallback: 'blocking', + }) +} diff --git a/apps/www/public/downloads/docs/Supabase+TIA+240401.pdf b/apps/www/public/downloads/docs/Supabase+TIA+240401.pdf new file mode 100644 index 00000000000..d2fbbe61dc7 Binary files /dev/null and b/apps/www/public/downloads/docs/Supabase+TIA+240401.pdf differ diff --git a/apps/www/public/favicon/browserconfig.xml b/apps/www/public/favicon/browserconfig.xml index c5541482230..1a8136def88 100644 --- a/apps/www/public/favicon/browserconfig.xml +++ b/apps/www/public/favicon/browserconfig.xml @@ -1,2 +1,2 @@ -#ffffff \ No newline at end of file +#ffffff \ No newline at end of file diff --git a/apps/www/public/favicon/favicon-180x180.png b/apps/www/public/favicon/favicon-180x180.png new file mode 100644 index 00000000000..456f3c7dd9d Binary files /dev/null and b/apps/www/public/favicon/favicon-180x180.png differ diff --git a/apps/www/public/favicon/favicon-48x48.png b/apps/www/public/favicon/favicon-48x48.png new file mode 100644 index 00000000000..eb6a7ec729a Binary files /dev/null and b/apps/www/public/favicon/favicon-48x48.png differ diff --git a/apps/www/public/favicon/manifest.json b/apps/www/public/favicon/manifest.json index 3a90d23e45e..4efcf18e2ec 100644 --- a/apps/www/public/favicon/manifest.json +++ b/apps/www/public/favicon/manifest.json @@ -7,37 +7,37 @@ "background_color": "#1C1C1C", "icons": [ { - "src": "/android-icon-36x36.png", + "src": "/favicon/android-icon-36x36.png", "sizes": "36x36", "type": "image/png", "density": "0.75" }, { - "src": "/android-icon-48x48.png", + "src": "/favicon/android-icon-48x48.png", "sizes": "48x48", "type": "image/png", "density": "1.0" }, { - "src": "/android-icon-72x72.png", + "src": "/favicon/android-icon-72x72.png", "sizes": "72x72", "type": "image/png", "density": "1.5" }, { - "src": "/android-icon-96x96.png", + "src": "/favicon/android-icon-96x96.png", "sizes": "96x96", "type": "image/png", "density": "2.0" }, { - "src": "/android-icon-144x144.png", + "src": "/favicon/android-icon-144x144.png", "sizes": "144x144", "type": "image/png", "density": "3.0" }, { - "src": "/android-icon-192x192.png", + "src": "/favicon/android-icon-192x192.png", "sizes": "192x192", "type": "image/png", "density": "4.0" diff --git a/apps/www/public/images/blog/2024-04-01-pg-paper-dump/historical-paper-backup.webp b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/historical-paper-backup.webp new file mode 100644 index 00000000000..6c2f031502f Binary files /dev/null and b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/historical-paper-backup.webp differ diff --git a/apps/www/public/images/blog/2024-04-01-pg-paper-dump/paper-container.jpeg b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/paper-container.jpeg new file mode 100644 index 00000000000..d900a67d334 Binary files /dev/null and b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/paper-container.jpeg differ diff --git a/apps/www/public/images/blog/2024-04-01-pg-paper-dump/pg-paper-dump-thumb.png b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/pg-paper-dump-thumb.png new file mode 100644 index 00000000000..09ba506e67b Binary files /dev/null and b/apps/www/public/images/blog/2024-04-01-pg-paper-dump/pg-paper-dump-thumb.png differ diff --git a/apps/www/public/images/launchweek/11/airpods-max-alpha-crop.png b/apps/www/public/images/launchweek/11/airpods-max-alpha-crop.png new file mode 100644 index 00000000000..b9e746ff3ff Binary files /dev/null and b/apps/www/public/images/launchweek/11/airpods-max-alpha-crop.png differ diff --git a/apps/www/public/images/launchweek/11/airpods-max-alpha.png b/apps/www/public/images/launchweek/11/airpods-max-alpha.png new file mode 100644 index 00000000000..fef70f2ebb6 Binary files /dev/null and b/apps/www/public/images/launchweek/11/airpods-max-alpha.png differ diff --git a/apps/www/public/images/launchweek/11/lw11-og.png b/apps/www/public/images/launchweek/11/lw11-og.png new file mode 100644 index 00000000000..b73fa580271 Binary files /dev/null and b/apps/www/public/images/launchweek/11/lw11-og.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/lw11_ticket_gold.png b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_gold.png new file mode 100644 index 00000000000..b1ec472ca6b Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_gold.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/lw11_ticket_platinum.png b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_platinum.png new file mode 100644 index 00000000000..4af219c5726 Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_platinum.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/lw11_ticket_regular_darker.png b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_regular_darker.png new file mode 100644 index 00000000000..afdd59f527b Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/lw11_ticket_regular_darker.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_platinum.png b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_platinum.png new file mode 100644 index 00000000000..b360c205508 Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_platinum.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_purple.png b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_purple.png new file mode 100644 index 00000000000..9cb2cf17d09 Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_purple.png differ diff --git a/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_regular.png b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_regular.png new file mode 100644 index 00000000000..80be4cb01c0 Binary files /dev/null and b/apps/www/public/images/launchweek/11/tickets/shape/lw11_ticket_regular.png differ diff --git a/apps/www/public/images/launchweek/2x-gold-ticket-background.jpg b/apps/www/public/images/launchweek/2x-gold-ticket-background.jpg deleted file mode 100644 index 2458ba6e641..00000000000 Binary files a/apps/www/public/images/launchweek/2x-gold-ticket-background.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/2x-regular-ticket-background.jpg b/apps/www/public/images/launchweek/2x-regular-ticket-background.jpg deleted file mode 100644 index e2bcd23470e..00000000000 Binary files a/apps/www/public/images/launchweek/2x-regular-ticket-background.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/PITR-visual-hover-light.svg b/apps/www/public/images/launchweek/PITR-visual-hover-light.svg deleted file mode 100644 index b1c339242dd..00000000000 --- a/apps/www/public/images/launchweek/PITR-visual-hover-light.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/PITR-visual-light.svg b/apps/www/public/images/launchweek/PITR-visual-light.svg deleted file mode 100644 index 4c9747c6d5f..00000000000 --- a/apps/www/public/images/launchweek/PITR-visual-light.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/PgGraphql-visual-hover-light.svg b/apps/www/public/images/launchweek/PgGraphql-visual-hover-light.svg deleted file mode 100644 index a1d5e9c1f43..00000000000 --- a/apps/www/public/images/launchweek/PgGraphql-visual-hover-light.svg +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/PgGraphql-visual-light.svg b/apps/www/public/images/launchweek/PgGraphql-visual-light.svg deleted file mode 100644 index 5f74d7bb177..00000000000 --- a/apps/www/public/images/launchweek/PgGraphql-visual-light.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/PostgREST11-visual-hover-light.svg b/apps/www/public/images/launchweek/PostgREST11-visual-hover-light.svg deleted file mode 100644 index d194dc6df07..00000000000 --- a/apps/www/public/images/launchweek/PostgREST11-visual-hover-light.svg +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/PostgREST11-visual-light.svg b/apps/www/public/images/launchweek/PostgREST11-visual-light.svg deleted file mode 100644 index b4f142b54ee..00000000000 --- a/apps/www/public/images/launchweek/PostgREST11-visual-light.svg +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/TCE-visual-hover-light.svg b/apps/www/public/images/launchweek/TCE-visual-hover-light.svg deleted file mode 100644 index 0059b38395e..00000000000 --- a/apps/www/public/images/launchweek/TCE-visual-hover-light.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/TCE-visual-light.svg b/apps/www/public/images/launchweek/TCE-visual-light.svg deleted file mode 100644 index c8730cb8927..00000000000 --- a/apps/www/public/images/launchweek/TCE-visual-light.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/antcopple.png b/apps/www/public/images/launchweek/antcopple.png deleted file mode 100644 index 769cd8b3b4f..00000000000 Binary files a/apps/www/public/images/launchweek/antcopple.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/blog post placeholder.jpg b/apps/www/public/images/launchweek/blog post placeholder.jpg deleted file mode 100644 index bcdced1a6f5..00000000000 Binary files a/apps/www/public/images/launchweek/blog post placeholder.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/blog-icon.svg b/apps/www/public/images/launchweek/blog-icon.svg deleted file mode 100644 index 7540a84898d..00000000000 --- a/apps/www/public/images/launchweek/blog-icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/apps/www/public/images/launchweek/blogpost.svg b/apps/www/public/images/launchweek/blogpost.svg deleted file mode 100644 index f3cd890cfeb..00000000000 --- a/apps/www/public/images/launchweek/blogpost.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/apps/www/public/images/launchweek/cdn-caching-bg-light.png b/apps/www/public/images/launchweek/cdn-caching-bg-light.png deleted file mode 100644 index 6fad05721a2..00000000000 Binary files a/apps/www/public/images/launchweek/cdn-caching-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/community-visual-light-hover.svg b/apps/www/public/images/launchweek/community-visual-light-hover.svg deleted file mode 100644 index 020fd56d4bd..00000000000 --- a/apps/www/public/images/launchweek/community-visual-light-hover.svg +++ /dev/null @@ -1,1046 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/community-visual-light.svg b/apps/www/public/images/launchweek/community-visual-light.svg deleted file mode 100644 index 2cd8d4b224e..00000000000 --- a/apps/www/public/images/launchweek/community-visual-light.svg +++ /dev/null @@ -1,1010 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/copple-placeholder.jpg b/apps/www/public/images/launchweek/copple-placeholder.jpg new file mode 100644 index 00000000000..f8939639d6d Binary files /dev/null and b/apps/www/public/images/launchweek/copple-placeholder.jpg differ diff --git a/apps/www/public/images/launchweek/custom-domains-visual-hover-light.svg b/apps/www/public/images/launchweek/custom-domains-visual-hover-light.svg deleted file mode 100644 index 78291133ced..00000000000 --- a/apps/www/public/images/launchweek/custom-domains-visual-hover-light.svg +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/custom-domains-visual-light.svg b/apps/www/public/images/launchweek/custom-domains-visual-light.svg deleted file mode 100644 index 2c1ad7bd8c4..00000000000 --- a/apps/www/public/images/launchweek/custom-domains-visual-light.svg +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/day1/thumb.jpg b/apps/www/public/images/launchweek/day1/thumb.jpg deleted file mode 100644 index 783f8bde69f..00000000000 Binary files a/apps/www/public/images/launchweek/day1/thumb.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/day2/thumb.jpg b/apps/www/public/images/launchweek/day2/thumb.jpg deleted file mode 100644 index fb6b788688e..00000000000 Binary files a/apps/www/public/images/launchweek/day2/thumb.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/day3/thumb.jpg b/apps/www/public/images/launchweek/day3/thumb.jpg deleted file mode 100644 index 9fe98a7d90e..00000000000 Binary files a/apps/www/public/images/launchweek/day3/thumb.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/day4/thumb.jpg b/apps/www/public/images/launchweek/day4/thumb.jpg deleted file mode 100644 index 4fbafc5d1dc..00000000000 Binary files a/apps/www/public/images/launchweek/day4/thumb.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/day5/thumb-old.jpg b/apps/www/public/images/launchweek/day5/thumb-old.jpg deleted file mode 100644 index 79c944bc84f..00000000000 Binary files a/apps/www/public/images/launchweek/day5/thumb-old.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/day5/thumb.jpg b/apps/www/public/images/launchweek/day5/thumb.jpg deleted file mode 100644 index ed7fe17f52a..00000000000 Binary files a/apps/www/public/images/launchweek/day5/thumb.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/docs-update-bg-light.png b/apps/www/public/images/launchweek/docs-update-bg-light.png deleted file mode 100644 index c08fbd148a6..00000000000 Binary files a/apps/www/public/images/launchweek/docs-update-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/docs-update-bg__.png b/apps/www/public/images/launchweek/docs-update-bg__.png deleted file mode 100644 index 12de95b1b48..00000000000 Binary files a/apps/www/public/images/launchweek/docs-update-bg__.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/docs.svg b/apps/www/public/images/launchweek/docs.svg deleted file mode 100644 index d682b98a8a8..00000000000 --- a/apps/www/public/images/launchweek/docs.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/apps/www/public/images/launchweek/encryption-bg-light.png b/apps/www/public/images/launchweek/encryption-bg-light.png deleted file mode 100644 index 9de76cf9127..00000000000 Binary files a/apps/www/public/images/launchweek/encryption-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/encryption-bg.png b/apps/www/public/images/launchweek/encryption-bg.png deleted file mode 100644 index 01dff450301..00000000000 Binary files a/apps/www/public/images/launchweek/encryption-bg.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/encryption-bg.svg b/apps/www/public/images/launchweek/encryption-bg.svg deleted file mode 100644 index 906921b7c9d..00000000000 --- a/apps/www/public/images/launchweek/encryption-bg.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/gold-ticket-background.png b/apps/www/public/images/launchweek/gold-ticket-background.png deleted file mode 100644 index 5cdf8d40a9c..00000000000 Binary files a/apps/www/public/images/launchweek/gold-ticket-background.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/golden-ticket.svg b/apps/www/public/images/launchweek/golden-ticket.svg deleted file mode 100644 index 201bffffbf6..00000000000 --- a/apps/www/public/images/launchweek/golden-ticket.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/green-ticket.svg b/apps/www/public/images/launchweek/green-ticket.svg deleted file mode 100644 index dda47904664..00000000000 --- a/apps/www/public/images/launchweek/green-ticket.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/icons-docs_.svg b/apps/www/public/images/launchweek/icons-docs_.svg deleted file mode 100644 index 274b20b8e4f..00000000000 --- a/apps/www/public/images/launchweek/icons-docs_.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/apps/www/public/images/launchweek/image-processing-bg-light-alt.png b/apps/www/public/images/launchweek/image-processing-bg-light-alt.png deleted file mode 100644 index de01c7bf28c..00000000000 Binary files a/apps/www/public/images/launchweek/image-processing-bg-light-alt.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/image-processing-bg-light.png b/apps/www/public/images/launchweek/image-processing-bg-light.png deleted file mode 100644 index 72eed0b732a..00000000000 Binary files a/apps/www/public/images/launchweek/image-processing-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/launchweek-logo--dark_old.svg b/apps/www/public/images/launchweek/launchweek-logo--dark_old.svg deleted file mode 100644 index 7153efa952a..00000000000 --- a/apps/www/public/images/launchweek/launchweek-logo--dark_old.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/launchweek-logo--light__old.svg b/apps/www/public/images/launchweek/launchweek-logo--light__old.svg deleted file mode 100644 index 4f5785bab9d..00000000000 --- a/apps/www/public/images/launchweek/launchweek-logo--light__old.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/launchweek-logo--light_old0.svg b/apps/www/public/images/launchweek/launchweek-logo--light_old0.svg deleted file mode 100644 index a2359311df5..00000000000 --- a/apps/www/public/images/launchweek/launchweek-logo--light_old0.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/mfa-bg-light.png b/apps/www/public/images/launchweek/mfa-bg-light.png deleted file mode 100644 index 6ee535ba251..00000000000 Binary files a/apps/www/public/images/launchweek/mfa-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/mfa-bg.png b/apps/www/public/images/launchweek/mfa-bg.png deleted file mode 100644 index 7ab2738a2e5..00000000000 Binary files a/apps/www/public/images/launchweek/mfa-bg.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/mfa-light-hover.png b/apps/www/public/images/launchweek/mfa-light-hover.png deleted file mode 100644 index 7abd2a8c38b..00000000000 Binary files a/apps/www/public/images/launchweek/mfa-light-hover.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/mfa-light.png b/apps/www/public/images/launchweek/mfa-light.png deleted file mode 100644 index d4038672ce3..00000000000 Binary files a/apps/www/public/images/launchweek/mfa-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/og-image.jpg b/apps/www/public/images/launchweek/og-image.jpg deleted file mode 100644 index 21c58be7988..00000000000 Binary files a/apps/www/public/images/launchweek/og-image.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/outro-light.svg b/apps/www/public/images/launchweek/outro-light.svg deleted file mode 100644 index f24f0760446..00000000000 --- a/apps/www/public/images/launchweek/outro-light.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/apps/www/public/images/launchweek/pg_crdt-visual-hover-light.svg b/apps/www/public/images/launchweek/pg_crdt-visual-hover-light.svg deleted file mode 100644 index 79e1c80a97c..00000000000 --- a/apps/www/public/images/launchweek/pg_crdt-visual-hover-light.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/pg_crdt-visual-light.svg b/apps/www/public/images/launchweek/pg_crdt-visual-light.svg deleted file mode 100644 index 7c3f559b59a..00000000000 --- a/apps/www/public/images/launchweek/pg_crdt-visual-light.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/pitr-bg-light.png b/apps/www/public/images/launchweek/pitr-bg-light.png deleted file mode 100644 index 5960c9314bd..00000000000 Binary files a/apps/www/public/images/launchweek/pitr-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/pitr-bg.png b/apps/www/public/images/launchweek/pitr-bg.png deleted file mode 100644 index efc950051d4..00000000000 Binary files a/apps/www/public/images/launchweek/pitr-bg.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/postgres-visual-hover-light.svg b/apps/www/public/images/launchweek/postgres-visual-hover-light.svg deleted file mode 100644 index a3116dbd48d..00000000000 --- a/apps/www/public/images/launchweek/postgres-visual-hover-light.svg +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/postgres-visual-light.svg b/apps/www/public/images/launchweek/postgres-visual-light.svg deleted file mode 100644 index aa5c513319b..00000000000 --- a/apps/www/public/images/launchweek/postgres-visual-light.svg +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/regular-ticket-background.png b/apps/www/public/images/launchweek/regular-ticket-background.png deleted file mode 100644 index 044d67a0de7..00000000000 Binary files a/apps/www/public/images/launchweek/regular-ticket-background.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/supabadge-connected.svg b/apps/www/public/images/launchweek/supabadge-connected.svg deleted file mode 100644 index 2a697b09bc9..00000000000 --- a/apps/www/public/images/launchweek/supabadge-connected.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/supabadge-disconnected.svg b/apps/www/public/images/launchweek/supabadge-disconnected.svg deleted file mode 100644 index 7c5fcd76a89..00000000000 --- a/apps/www/public/images/launchweek/supabadge-disconnected.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/supabadge-gold.svg b/apps/www/public/images/launchweek/supabadge-gold.svg deleted file mode 100644 index 17cbf3b680f..00000000000 --- a/apps/www/public/images/launchweek/supabadge-gold.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/supabase-launch-week-5-bg--light.jpg b/apps/www/public/images/launchweek/supabase-launch-week-5-bg--light.jpg deleted file mode 100644 index c7b26f1edfc..00000000000 Binary files a/apps/www/public/images/launchweek/supabase-launch-week-5-bg--light.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/supabase-launch-week-5-bg.jpg b/apps/www/public/images/launchweek/supabase-launch-week-5-bg.jpg deleted file mode 100644 index 98c373f9cff..00000000000 Binary files a/apps/www/public/images/launchweek/supabase-launch-week-5-bg.jpg and /dev/null differ diff --git a/apps/www/public/images/launchweek/ticket-header-logo.svg b/apps/www/public/images/launchweek/ticket-header-logo.svg deleted file mode 100644 index 96613bac403..00000000000 --- a/apps/www/public/images/launchweek/ticket-header-logo.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/apps/www/public/images/launchweek/vault-bg-light.png b/apps/www/public/images/launchweek/vault-bg-light.png deleted file mode 100644 index 50ae3c9462f..00000000000 Binary files a/apps/www/public/images/launchweek/vault-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/vault-bg.png b/apps/www/public/images/launchweek/vault-bg.png deleted file mode 100644 index 2b927dcbab8..00000000000 Binary files a/apps/www/public/images/launchweek/vault-bg.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/vault-visual-hover-light.svg b/apps/www/public/images/launchweek/vault-visual-hover-light.svg deleted file mode 100644 index fef124cca82..00000000000 --- a/apps/www/public/images/launchweek/vault-visual-hover-light.svg +++ /dev/null @@ -1,548 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/vault-visual-light.svg b/apps/www/public/images/launchweek/vault-visual-light.svg deleted file mode 100644 index 768b527e4a5..00000000000 --- a/apps/www/public/images/launchweek/vault-visual-light.svg +++ /dev/null @@ -1,547 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/wrappers-bg-light.png b/apps/www/public/images/launchweek/wrappers-bg-light.png deleted file mode 100644 index e70745d217c..00000000000 Binary files a/apps/www/public/images/launchweek/wrappers-bg-light.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/wrappers-bg.png b/apps/www/public/images/launchweek/wrappers-bg.png deleted file mode 100644 index cef57946f8b..00000000000 Binary files a/apps/www/public/images/launchweek/wrappers-bg.png and /dev/null differ diff --git a/apps/www/public/images/launchweek/wrappers-bg.svg b/apps/www/public/images/launchweek/wrappers-bg.svg deleted file mode 100644 index 7e447c9648d..00000000000 --- a/apps/www/public/images/launchweek/wrappers-bg.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/wrappers-visual-hover-light.svg b/apps/www/public/images/launchweek/wrappers-visual-hover-light.svg deleted file mode 100644 index 3e54e814ec0..00000000000 --- a/apps/www/public/images/launchweek/wrappers-visual-hover-light.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/wrappers-visual-light.svg b/apps/www/public/images/launchweek/wrappers-visual-light.svg deleted file mode 100644 index 105ea201435..00000000000 --- a/apps/www/public/images/launchweek/wrappers-visual-light.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/www/public/images/launchweek/wrapup.svg b/apps/www/public/images/launchweek/wrapup.svg deleted file mode 100644 index 098cdc6b7b9..00000000000 --- a/apps/www/public/images/launchweek/wrapup.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/apps/www/public/rss.xml b/apps/www/public/rss.xml index 5bd3a23686a..4524ba5e84b 100644 --- a/apps/www/public/rss.xml +++ b/apps/www/public/rss.xml @@ -5,14 +5,28 @@ https://supabase.com Latest news from Supabase en - Wed, 28 Feb 2024 06:00:00 GMT + Wed, 28 Feb 2024 23:00:00 GMT - + https://supabase.com/blog/postgrest-aggregate-functions PostgREST Aggregate Functions https://supabase.com/blog/postgrest-aggregate-functions - Usage of Aggregate functions on PostgREST 12 - Wed, 28 Feb 2024 06:00:00 GMT + Summarize your data by performing calculations across groups of rows in PostgREST + Wed, 28 Feb 2024 23:00:00 GMT + + + https://supabase.com/blog/content-recommendation-with-flutter + Build a content recommendation app with Flutter and OpenAI + https://supabase.com/blog/content-recommendation-with-flutter + Build a movie-viewing app that recommends another movie based on what the user is viewing using OpenAI, Flutter and Supabase. + Sun, 25 Feb 2024 23:00:00 GMT + + + https://supabase.com/blog/automating-performance-tests + Automating performance tests + https://supabase.com/blog/automating-performance-tests + Learn about our story to get to the automated performance testing. + Tue, 20 Feb 2024 23:00:00 GMT https://supabase.com/blog/matryoshka-embeddings diff --git a/apps/www/supabase/functions/launchweek-ticket-og/README.md b/apps/www/supabase/functions/launchweek-ticket-og/README.md deleted file mode 100644 index 50104fcea85..00000000000 --- a/apps/www/supabase/functions/launchweek-ticket-og/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Open Graph (OG) Image Generation with Supabase Storage CDN Caching - -Generate Open Graph images with Deno and Supabase Edge Functions and cache the generated image with Supabase Storage CDN. - -- Docs: https://deno.land/x/og_edge@0.0.2 -- Examples: https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples -- Demo: https://obuldanrptloktxcffvn.supabase.co/functions/v1/launchweek-ticket-og?username=thorwebdev - -## Run locally - -```bash -supabase functions serve launchweek-ticket-og --no-verify-jwt -``` - -Navigate to http://localhost:54321/functions/v1/launchweek-ticket-og?username=thorwebdev - -## Deploy - -```bash -supabase functions deploy launchweek-ticket-og --no-verify-jwt -``` diff --git a/apps/www/supabase/functions/launchweek-ticket-og/handler.tsx b/apps/www/supabase/functions/launchweek-ticket-og/handler.tsx deleted file mode 100644 index c35b8b8cd3b..00000000000 --- a/apps/www/supabase/functions/launchweek-ticket-og/handler.tsx +++ /dev/null @@ -1,242 +0,0 @@ -import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' -import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' -import { corsHeaders } from '../_shared/cors.ts' - -const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw6' -const BACKGROUND_IMAGE_STD = `${STORAGE_URL}/lw6_ticket_regular.png?prod=true&v=2` -const BACKGROUND_IMAGE_GOLDEN = `${STORAGE_URL}/lw6_ticket_gold.png?prod=true&v=2` -const SUPA_CHECKMARK = `${STORAGE_URL}/supaverified.png?prod=true&v=2` -const SUPA_CHECKMARK_GOLD = `${STORAGE_URL}/supaverified_gold.png?prod=true&v=2` - -// Load custom font -const FONT_URL = `${STORAGE_URL}/CircularStd-Book.otf?prod=true&v=2` -const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) - -export async function handler(req: Request) { - const url = new URL(req.url) - const username = url.searchParams.get('username') ?? url.searchParams.get('amp;username') - const userAgent = req.headers.get('user-agent') - - try { - if (!username) throw new Error('missing username param') - // Track social shares - const supabaseAdminClient = createClient( - // Supabase API URL - env var exported by default when deployed. - Deno.env.get('SUPABASE_URL') ?? '', - // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' - ) - if (userAgent?.toLocaleLowerCase().includes('twitter')) { - const { error } = await supabaseAdminClient - .from('lw6_tickets') - .update({ sharedOnTwitter: true }) - .eq('username', username) - if (error) console.log(error.message) - } else if (userAgent?.toLocaleLowerCase().includes('linkedin')) { - const { error } = await supabaseAdminClient - .from('lw6_tickets') - .update({ sharedOnLinkedIn: true }) - .eq('username', username) - if (error) console.log(error.message) - } - - // Try to get image from Supabase Storage CDN. - const storageResponse = await fetch(`${STORAGE_URL}/tickets/${username}.png?prod=true&v=5`) - if (storageResponse.ok) return storageResponse - - // Get ticket data - const { data, error } = await supabaseAdminClient - .from('lw6_tickets_golden') - .select('name, ticketNumber, golden') - .eq('username', username) - .maybeSingle() - if (error) throw error - - if (!data?.ticketNumber) throw new Error('missing data') - const { name, ticketNumber } = data - const golden = data?.golden ?? false - - // Else, generate image ad upload to storage. - const fontData = await font - const numDigits = `${Number(ticketNumber)}`.length - const prefix = `00000000`.slice(numDigits) - - const generatedImage = new ImageResponse( - ( - <> -
    - {/* Background image */} - - {/* GitHub Avatar image */} - - {/* Name & username */} -
    -
    -

    - {name ?? username} -

    -
    - {/* Username and supaverified checkmark */} -
    - {`@${username}`} - - - -
    -
    - {/* Date */} -

    - December 12th 2022 -

    - {/* URL */} -

    - supabase.com/launch-week -

    -
    - {/* Ticket No */} -
    -

    - {`No ${prefix}${ticketNumber}`} -

    -
    - - ), - { - width: 1200, - height: 630, - fonts: [ - { - name: 'Circular', - data: fontData, - style: 'normal', - }, - ], - headers: { - 'content-type': 'image/png', - 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', - 'cdn-cache-control': 'max-age=31536000', - }, - } - ) - - // Upload image to storage. - const { error: storageError } = await supabaseAdminClient.storage - .from('images') - .upload(`lw6/tickets/${username}.png`, generatedImage.body!, { - contentType: 'image/png', - cacheControl: '31536000', - upsert: false, - }) - if (storageError) throw storageError - - return generatedImage - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 400, - }) - } -} diff --git a/apps/www/supabase/functions/launchweek-ticket-og/index.ts b/apps/www/supabase/functions/launchweek-ticket-og/index.ts deleted file mode 100644 index 7da9ffc001b..00000000000 --- a/apps/www/supabase/functions/launchweek-ticket-og/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -import { serve } from 'https://deno.land/std@0.140.0/http/server.ts' - -import { handler } from './handler.tsx' - -console.log(`Function "launchweek-ticket-og" up and running!`) - -serve(handler) diff --git a/apps/www/supabase/functions/lw7-ticket-og/README.md b/apps/www/supabase/functions/lw11-og/README.md similarity index 63% rename from apps/www/supabase/functions/lw7-ticket-og/README.md rename to apps/www/supabase/functions/lw11-og/README.md index 08ac5c8bfc9..1fe3e27a5d7 100644 --- a/apps/www/supabase/functions/lw7-ticket-og/README.md +++ b/apps/www/supabase/functions/lw11-og/README.md @@ -4,18 +4,19 @@ Generate Open Graph images with Deno and Supabase Edge Functions and cache the g - Docs: https://deno.land/x/og_edge@0.0.2 - Examples: https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples -- Demo: https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw7-ticket-og?username=thorwebdev +- Demo: https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw11-og?username= ## Run locally ```bash -supabase functions serve --no-verify-jwt +supabase start +supabase functions serve lw11-og --no-verify-jwt --env-file ./supabase/.env.local ``` -Navigate to http://localhost:54321/functions/v1/lw7-ticket-og?username=thorwebdev +Navigate to http://localhost:54321/functions/v1/lw11-og?username= ## Deploy ```bash -supabase functions deploy lw7-ticket-og --no-verify-jwt +supabase functions deploy lw11-og --no-verify-jwt ``` diff --git a/apps/www/supabase/functions/lw11-og/handler.tsx b/apps/www/supabase/functions/lw11-og/handler.tsx new file mode 100644 index 00000000000..4ec3ae7f0de --- /dev/null +++ b/apps/www/supabase/functions/lw11-og/handler.tsx @@ -0,0 +1,419 @@ +import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' +import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' +import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' + +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', +} + +const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw11' + +// Load custom font +const FONT_URL = `${STORAGE_URL}/assets/font/CircularStd-Book.otf` +const MONO_FONT_URL = `${STORAGE_URL}/assets/font/SourceCodePro-Regular.ttf` +const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) +const mono_font = fetch(new URL(MONO_FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) +// const BUCKET_FOLDER_VERSION = 'v1' + +const LW_TABLE = 'lw11_tickets' +const LW_MATERIALIZED_VIEW = 'lw11_tickets_platinum' + +const STYLING_CONGIF = { + regular: { + BACKGROUND: '#f1f1f1', + FOREGROUND: '#11181C', + FOREGROUND_LIGHT: '#6c7277', + TICKET_FOREGROUND: '#F8F9FA', + TICKET_FOREGROUND_LIGHT: '#8B9092', + BORDER: '#4e4e4e', + }, + platinum: { + BACKGROUND: '#060809', + FOREGROUND: '#F8F9FA', + FOREGROUND_LIGHT: '#8B9092', + TICKET_FOREGROUND: '#11181C', + TICKET_FOREGROUND_LIGHT: '#6c7277', + BORDER: '#adadad', + }, + secret: { + BACKGROUND: '#060809', + FOREGROUND: '#F8F9FA', + FOREGROUND_LIGHT: '#8B9092', + TICKET_FOREGROUND: '#F8F9FA', + TICKET_FOREGROUND_LIGHT: '#F8F9FA', + BORDER: '#959595', + }, +} + +export async function handler(req: Request) { + const url = new URL(req.url) + const username = url.searchParams.get('username') ?? url.searchParams.get('amp;username') + const assumePlatinum = url.searchParams.get('platinum') ?? url.searchParams.get('amp;platinum') + const userAgent = req.headers.get('user-agent') + + try { + if (!username) throw new Error('missing username param') + + const supabaseAdminClient = createClient( + // Supabase API URL - env var exported by default when deployed. + Deno.env.get('MISC_USE_URL') ?? '', + // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. + Deno.env.get('MISC_USE_ANON_KEY') ?? '' + ) + + // Track social shares + if (userAgent?.toLocaleLowerCase().includes('twitter')) { + await supabaseAdminClient + .from(LW_TABLE) + .update({ sharedOnTwitter: 'now' }) + .eq('username', username) + .is('sharedOnTwitter', null) + } else if (userAgent?.toLocaleLowerCase().includes('linkedin')) { + await supabaseAdminClient + .from(LW_TABLE) + .update({ sharedOnLinkedIn: 'now' }) + .eq('username', username) + .is('sharedOnLinkedIn', null) + } + + // Get ticket data + const { data, error } = await supabaseAdminClient + .from(LW_MATERIALIZED_VIEW) + .select('name, ticketNumber, sharedOnTwitter, sharedOnLinkedIn, metadata, secret') + .eq('username', username) + .maybeSingle() + + if (error) console.log('fetch error', error.message) + if (!data) throw new Error(error?.message ?? 'user not found') + const { name, ticketNumber, metadata, secret } = data + + const platinum = (!!data?.sharedOnTwitter && !!data?.sharedOnLinkedIn) ?? false + if (assumePlatinum && !platinum) + return await fetch(`${STORAGE_URL}/assets/platinum_no_meme.jpg`) + + // Generate image and upload to storage. + const ticketType = secret ? 'secret' : platinum ? 'platinum' : 'regular' + + const fontData = await font + const monoFontData = await mono_font + const numDigits = `${Number(ticketNumber)}`.length + const prefix = `0000000`.slice(numDigits) + const HAS_ROLE = !!metadata?.role + const HAS_COMPANY = !!metadata?.company + const HAS_LOCATION = !!metadata?.location + const HAS_AVATAR = !metadata?.hideAvatar + const HAS_NO_META = !HAS_ROLE && !HAS_COMPANY && !HAS_LOCATION + const OG_WIDTH = 1200 + const OG_HEIGHT = 628 + const OG_PADDING_X = 60 + const OG_PADDING_Y = 60 + const TICKET_WIDTH = 600 + const TICKET_RATIO = 396 / 613 + const TICKET_HEIGHT = TICKET_WIDTH / TICKET_RATIO + const TICKET_POS_TOP = OG_PADDING_Y + const TICKET_POS_LEFT = 540 + const TICKET_PADDING_X = 40 + const TICKET_PADDING_Y = 40 + const LOGO_WIDTH = 40 + // const LOGO_RATIO = 581 / 113 + const LOGO_RATIO = 436 / 449 + // Select one of 30 pre generated bg images base on ticket number + const BG_NUMBER = `000${(ticketNumber % 30) + 1}`.slice(-3) + const profileImg = `https://github.com/${username}.png?size=100` + const DISPLAY_NAME = name ?? username + + const BACKGROUND = { + regular: { + OG: `${STORAGE_URL}/assets/backgrounds/platinum/${BG_NUMBER}.png`, + BG: `${STORAGE_URL}/assets/shape/v2/lw11_ticket_regular.png?t=1`, + LOGO: `${STORAGE_URL}/assets/supabase/supabase-logo-icon.png`, + }, + platinum: { + OG: `${STORAGE_URL}/assets/backgrounds/regular/${BG_NUMBER}.png`, + BG: `${STORAGE_URL}/assets/shape/v2/lw11_ticket_platinum.png?t=1`, + LOGO: `${STORAGE_URL}/assets/supabase/supabase-logo-icon.png`, + }, + secret: { + OG: `${STORAGE_URL}/assets/backgrounds/secret/${BG_NUMBER}.png`, + BG: `${STORAGE_URL}/assets/shape/v2/lw11_ticket_purple.png?t=1`, + LOGO: `${STORAGE_URL}/assets/supabase/supabase-logo-icon.png`, + }, + } + + const generatedTicketImage = new ImageResponse( + ( + <> +
    + {/* Background */} + + {/* Ticket */} +
    + + + {/* Ticket No */} +

    + {`NO ${prefix}${ticketNumber}`} +

    + + {/* Name & username */} +
    + {HAS_AVATAR && ( + + )} +

    + {DISPLAY_NAME} +

    + +
    + {HAS_NO_META && username && `@${username}`} + {HAS_ROLE && `${metadata.role}`} + {HAS_COMPANY && `${HAS_ROLE ? ' at ' : ''}${metadata.company} `} +
    +
    +
    + +
    +
    + +
    + +

    + + Join us for a + + + Special Announcement + +

    +

    + April 15-19 / 7AM PT +

    +
    +
    + + ), + { + width: OG_WIDTH, + height: OG_HEIGHT, + fonts: [ + { + name: 'Circular', + data: fontData, + style: 'normal', + }, + { + name: 'SourceCodePro', + data: monoFontData, + style: 'normal', + }, + ], + headers: { + 'content-type': 'image/png', + 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', + 'cdn-cache-control': 'max-age=31536000', + }, + } + ) + + // Upload image to storage. + const { error: storageError } = await supabaseAdminClient.storage + .from('images') + .upload(`lw11/og/${ticketType}/${username}.png`, generatedTicketImage.body!, { + contentType: 'image/png', + // cacheControl: `${60 * 60 * 24 * 7}`, + cacheControl: `0`, + // Update cached og image, people might need to update info + upsert: true, + }) + + if (storageError) throw new Error(`storageError: ${storageError.message}`) + + const NEW_TIMESTAMP = new Date() + + return await fetch(`${STORAGE_URL}/og/${ticketType}/${username}.png?t=${NEW_TIMESTAMP}`) + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + status: 400, + }) + } +} diff --git a/apps/www/supabase/functions/lw8-ticket/index.ts b/apps/www/supabase/functions/lw11-og/index.ts similarity index 86% rename from apps/www/supabase/functions/lw8-ticket/index.ts rename to apps/www/supabase/functions/lw11-og/index.ts index 84d78bdf295..53f5af7e4bc 100644 --- a/apps/www/supabase/functions/lw8-ticket/index.ts +++ b/apps/www/supabase/functions/lw11-og/index.ts @@ -6,6 +6,6 @@ import { serve } from 'https://deno.land/std@0.168.0/http/server.ts' import { handler } from './handler.tsx' -console.log(`Function "lw8-ticket" up and running`) +console.log(`Function "lw11-og" up and running`) serve(handler) diff --git a/apps/www/supabase/functions/lw7-ticket-gallery/handler.tsx b/apps/www/supabase/functions/lw7-ticket-gallery/handler.tsx deleted file mode 100644 index 4947b1c5c19..00000000000 --- a/apps/www/supabase/functions/lw7-ticket-gallery/handler.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' -import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' -import { corsHeaders } from '../_shared/cors.ts' - -const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw7' - -// Load custom font -const FONT_URL = `${STORAGE_URL}/CircularStd-Book.otf` -const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) -const BUCKET_FOLDER_VERSION = 'v3' - -export async function handler(req: Request) { - try { - if (req.method !== 'POST') throw new Error('method not supported') - const { - username = 'thorwebdev', - name = 'Thoggen Schaeppy', - ticketNumber = 1234, - golden = true, - bg_image_id = 80, - }: { - username?: string - name?: string - ticketNumber?: number - golden?: boolean - bg_image_id?: number - } = await req.json() - - // Else, generate image ad upload to storage. - const BACKGROUND = { - REG: { - AI: `${STORAGE_URL}/tickets_bg/blurred/regular/png/reg_bg_${bg_image_id}.png`, - TICKET: `${STORAGE_URL}/reg_ticket_overlay.png`, - }, - GOLD: { - AI: `${STORAGE_URL}/tickets_bg/blurred/golden/png/gold_bg_${bg_image_id}.png`, - TICKET: `${STORAGE_URL}/gold_ticket_overlay.png`, - }, - } - - const fontData = await font - const numDigits = `${Number(ticketNumber)}`.length - const prefix = `00000000`.slice(numDigits) - - const generatedImage = new ImageResponse( - ( - <> -
    - {/* Background ai */} - - {/* Background ticket */} - - {/* GitHub Avatar image */} - - {/* Name & username */} -
    -
    -

    - {name ?? username} -

    {' '} -
    - - {/* Username */} -
    - {`@${username}`} -
    -
    -
    - {/* Ticket No */} -
    -

    - {`No ${prefix}${ticketNumber}`} -

    -
    - - ), - { - width: 1027, - height: 520, - fonts: [ - { - name: 'Circular', - data: fontData, - style: 'normal', - }, - ], - headers: { - 'content-type': 'image/png', - 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', - 'cdn-cache-control': 'max-age=31536000', - }, - } - ) - - // Upload image to storage. - const supabaseAdminClient = createClient( - // Supabase API URL - env var exported by default when deployed. - Deno.env.get('SUPABASE_URL') ?? '', - // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' - ) - const { error: storageError } = await supabaseAdminClient.storage - .from('images') - .upload( - `lw7/tickets/gallery/${ - golden ? 'golden' : 'regular' - }/${BUCKET_FOLDER_VERSION}/${username}.png`, - generatedImage.body!, - { - contentType: 'image/png', - cacheControl: '31536000', - upsert: true, - } - ) - if (storageError) throw new Error(`storageError: ${storageError.message}`) - - return new Response(JSON.stringify({ success: true }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 200, - }) - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 400, - }) - } -} diff --git a/apps/www/supabase/functions/lw7-ticket-gallery/index.ts b/apps/www/supabase/functions/lw7-ticket-gallery/index.ts deleted file mode 100644 index c24f7c7b2c8..00000000000 --- a/apps/www/supabase/functions/lw7-ticket-gallery/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -import { serve } from 'https://deno.land/std@0.177.0/http/server.ts' - -import { handler } from './handler.tsx' - -console.log(`Function "lw7-ticket-gallery" up and running!`) - -serve(handler) diff --git a/apps/www/supabase/functions/lw7-ticket-og/handler.tsx b/apps/www/supabase/functions/lw7-ticket-og/handler.tsx deleted file mode 100644 index b1a7c95d3e5..00000000000 --- a/apps/www/supabase/functions/lw7-ticket-og/handler.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' -import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' -import { corsHeaders } from '../_shared/cors.ts' - -const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw7' - -// Load custom font -const FONT_URL = `${STORAGE_URL}/CircularStd-Book.otf` -const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) -const BUCKET_FOLDER_VERSION = 'v3' - -export async function handler(req: Request) { - const url = new URL(req.url) - const username = url.searchParams.get('username') ?? url.searchParams.get('amp;username') - const assumeGolden = url.searchParams.get('golden') ?? url.searchParams.get('amp;golden') - const userAgent = req.headers.get('user-agent') - - try { - if (!username) throw new Error('missing username param') - // Track social shares - const supabaseAdminClient = createClient( - // Supabase API URL - env var exported by default when deployed. - Deno.env.get('SUPABASE_URL') ?? '', - // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' - ) - if (userAgent?.toLocaleLowerCase().includes('twitter')) { - await supabaseAdminClient - .from('lw7_tickets') - .update({ sharedOnTwitter: 'now' }) - .eq('username', username) - .is('sharedOnTwitter', null) - } else if (userAgent?.toLocaleLowerCase().includes('linkedin')) { - await supabaseAdminClient - .from('lw7_tickets') - .update({ sharedOnLinkedIn: 'now' }) - .eq('username', username) - .is('sharedOnLinkedIn', null) - } - - // Try to get image from Supabase Storage CDN. - let storageResponse: Response - storageResponse = await fetch( - `${STORAGE_URL}/tickets/golden/${BUCKET_FOLDER_VERSION}/${username}.png` - ) - if (storageResponse.ok) return storageResponse - storageResponse = await fetch( - `${STORAGE_URL}/tickets/regular/${BUCKET_FOLDER_VERSION}/${username}.png` - ) - if (!assumeGolden && storageResponse.ok) return storageResponse - - // Get ticket data - const { data, error } = await supabaseAdminClient - .from('lw7_tickets_golden') - .select('name, ticketNumber, golden, bg_image_id') - .eq('username', username) - .maybeSingle() - if (error) console.log(error.message) - if (!data) throw new Error('user not found') - const { name, ticketNumber, bg_image_id } = data - const golden = data?.golden ?? false - - if (assumeGolden && !golden) return await fetch(`${STORAGE_URL}/golden_no_meme.png`) - - // Else, generate image ad upload to storage. - const BACKGROUND = { - REG: { - BG: `${STORAGE_URL}/reg_bg.png`, - AI: `${STORAGE_URL}/tickets_bg/blurred/regular/png/reg_bg_${bg_image_id ?? '1'}.png`, - TICKET: `${STORAGE_URL}/reg_ticket.png`, - }, - GOLD: { - BG: `${STORAGE_URL}/gold_bg.png`, - AI: `${STORAGE_URL}/tickets_bg/blurred/golden/png/gold_bg_${bg_image_id ?? '1'}.png`, - TICKET: `${STORAGE_URL}/gold_ticket.png`, - }, - } - - const fontData = await font - const numDigits = `${Number(ticketNumber)}`.length - const prefix = `00000000`.slice(numDigits) - - const generatedImage = new ImageResponse( - ( - <> -
    - {/* Background gradient */} - - {/* Background ai */} - - {/* Background ticket */} - - {/* GitHub Avatar image */} - - {/* Name & username */} -
    -
    -

    - {name ?? username} -

    {' '} -
    - - {/* Username */} -
    - {`@${username}`} -
    -
    -
    - {/* Ticket No */} -
    -

    - {`No ${prefix}${ticketNumber}`} -

    -
    - - ), - { - width: 1200, - height: 630, - fonts: [ - { - name: 'Circular', - data: fontData, - style: 'normal', - }, - ], - headers: { - 'content-type': 'image/png', - 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', - 'cdn-cache-control': 'max-age=31536000', - }, - } - ) - - // Upload image to storage. - const { error: storageError } = await supabaseAdminClient.storage - .from('images') - .upload( - `lw7/tickets/${golden ? 'golden' : 'regular'}/${BUCKET_FOLDER_VERSION}/${username}.png`, - generatedImage.body!, - { - contentType: 'image/png', - cacheControl: '31536000', - upsert: false, - } - ) - if (storageError) throw new Error(`storageError: ${storageError.message}`) - // Generate image for gallery - fetch('https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw7-ticket-gallery', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9idWxkYW5ycHRsb2t0eGNmZnZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTIyNjkzMjYsImV4cCI6MjAwNzg0NTMyNn0.1S6qpBbHtEmGuMsIx5UOhRiFd4YbVv-yLTrLk6tVGmM', - }, - body: JSON.stringify({ - username, - name, - ticketNumber, - bg_image_id, - golden, - }), - }) - - return await fetch( - `${STORAGE_URL}/tickets/${ - golden ? 'golden' : 'regular' - }/${BUCKET_FOLDER_VERSION}/${username}.png` - ) - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 400, - }) - } -} diff --git a/apps/www/supabase/functions/lw7-ticket-og/index.ts b/apps/www/supabase/functions/lw7-ticket-og/index.ts deleted file mode 100644 index 97fbf105d96..00000000000 --- a/apps/www/supabase/functions/lw7-ticket-og/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -import { serve } from 'https://deno.land/std@0.177.0/http/server.ts' - -import { handler } from './handler.tsx' - -console.log(`Function "lw7-ticket-og" up and running!`) - -serve(handler) diff --git a/apps/www/supabase/functions/lw8-ticket-og/handler.tsx b/apps/www/supabase/functions/lw8-ticket-og/handler.tsx deleted file mode 100644 index 4794d65b5d7..00000000000 --- a/apps/www/supabase/functions/lw8-ticket-og/handler.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' -import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' -import { corsHeaders } from '../_shared/cors.ts' - -const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw8' - -const BUCKET_FOLDER_VERSION = 'v1' - -export async function handler(req: Request) { - try { - if (req.method !== 'POST') throw new Error('method not supported') - const { - username = 'thorwebdev', - golden = false, - }: { - username?: string - golden?: boolean - } = await req.json() - - // Else, generate image and upload to storage. - const timestamp = encodeURI(new Date().toISOString()) - const ticketImg = `${STORAGE_URL}/tickets/${ - golden ? 'golden' : 'regular' - }/${BUCKET_FOLDER_VERSION}/${username}.png?t=${timestamp}` - - const bgImg = `${STORAGE_URL}/assets/backgrounds/og-${golden ? 'golden' : 'regular'}.png` - const ticketWidth = 1100 - const ticketHeight = ticketWidth / 2 - const boxOffset = 24 - const boxWidth = `${ticketWidth + boxOffset}px` - const boxHeight = `${ticketHeight + boxOffset}px` - const leftOffset = `${(1200 - ticketWidth) / 2 - boxOffset / 2}px` - const topOffset = `${(628 - ticketHeight) / 2 - boxOffset / 2}px` - - const geneartedOGImage = new ImageResponse( - ( -
    - {/* Background */} - - {/* Ticket Box */} -
    - {/* Ticket */} - -
    - ), - { - width: 1200, - height: 628, - headers: { - 'content-type': 'image/png', - 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', - 'cdn-cache-control': 'max-age=31536000', - }, - } - ) - - // Upload image to storage. - const supabaseAdminClient = createClient( - // Supabase API URL - env var exported by default when deployed. - Deno.env.get('SUPABASE_URL') ?? '', - // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' - ) - const { error: storageError } = await supabaseAdminClient.storage - .from('images') - .upload( - `lw8/og/${golden ? 'golden' : 'regular'}/${BUCKET_FOLDER_VERSION}/${username}.png`, - geneartedOGImage.body!, - { - contentType: 'image/png', - cacheControl: '0', - upsert: true, - } - ) - if (storageError) throw new Error(`storageError: ${storageError.message}`) - // return geneartedOGImage - - return new Response(JSON.stringify({ success: true }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 200, - }) - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 400, - }) - } -} diff --git a/apps/www/supabase/functions/lw8-ticket-og/index.ts b/apps/www/supabase/functions/lw8-ticket-og/index.ts deleted file mode 100644 index 26986700825..00000000000 --- a/apps/www/supabase/functions/lw8-ticket-og/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -import { serve } from 'https://deno.land/std@0.177.0/http/server.ts' - -import { handler } from './handler.tsx' - -console.log(`Function "lw8-ticket-og" up and running`) - -serve(handler) diff --git a/apps/www/supabase/functions/lw8-ticket/README.md b/apps/www/supabase/functions/lw8-ticket/README.md deleted file mode 100644 index b7f60e0f9ec..00000000000 --- a/apps/www/supabase/functions/lw8-ticket/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Open Graph (OG) Image Generation with Supabase Storage CDN Caching - -Generate Open Graph images with Deno and Supabase Edge Functions and cache the generated image with Supabase Storage CDN. - -- Docs: https://deno.land/x/og_edge@0.0.2 -- Examples: https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples -- Demo: https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw8-ticket?username=thorwebdev - -## Run locally - -```bash -supabase functions serve lw8-ticket --no-verify-jwt -``` - -Navigate to http://localhost:54321/functions/v1/lw8-ticket?username=thorwebdev - -## Deploy - -```bash -supabase functions deploy lw8-ticket --no-verify-jwt -``` diff --git a/apps/www/supabase/functions/lw8-ticket/handler.tsx b/apps/www/supabase/functions/lw8-ticket/handler.tsx deleted file mode 100644 index 57c8d597fe4..00000000000 --- a/apps/www/supabase/functions/lw8-ticket/handler.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' -import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.7.1' -import { corsHeaders } from '../_shared/cors.ts' - -const STORAGE_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw8' - -// Load custom font -const FONT_URL = `${STORAGE_URL}/font/CircularStd-Book.otf` -const MONO_FONT_URL = `${STORAGE_URL}/font/SourceCodePro-Regular.ttf?t=2023-07-18T13%3A03%3A29.474Z` -const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) -const mono_font = fetch(new URL(MONO_FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) -const BUCKET_FOLDER_VERSION = 'v1' - -const LW_TABLE = 'lw8_tickets_golden' - -export async function handler(req: Request) { - const url = new URL(req.url) - const username = url.searchParams.get('username') ?? url.searchParams.get('amp;username') - const assumeGolden = url.searchParams.get('golden') ?? url.searchParams.get('amp;golden') - const userAgent = req.headers.get('user-agent') - - try { - if (!username) throw new Error('missing username param') - - const supabaseAdminClient = createClient( - // Supabase API URL - env var exported by default when deployed. - Deno.env.get('SUPABASE_URL') ?? '', - // Supabase API SERVICE ROLE KEY - env var exported by default when deployed. - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' - ) - - // Track social shares - if (userAgent?.toLocaleLowerCase().includes('twitter')) { - await supabaseAdminClient - .from(LW_TABLE) - .update({ sharedOnTwitter: 'now' }) - .eq('username', username) - .is('sharedOnTwitter', null) - } else if (userAgent?.toLocaleLowerCase().includes('linkedin')) { - await supabaseAdminClient - .from(LW_TABLE) - .update({ sharedOnLinkedIn: 'now' }) - .eq('username', username) - .is('sharedOnLinkedIn', null) - } - - // Get ticket data - const { data, error } = await supabaseAdminClient - .from(LW_TABLE) - .select('name, ticketNumber, sharedOnTwitter, sharedOnLinkedIn, metadata') - .eq('username', username) - .maybeSingle() - - if (error) console.log(error.message) - if (!data) throw new Error(error?.message ?? 'user not found') - const { name, ticketNumber, metadata } = data - - const golden = (!!data?.sharedOnTwitter && !!data?.sharedOnLinkedIn) ?? false - if (assumeGolden && !golden) return await fetch(`${STORAGE_URL}/golden_no_meme.png`) - - // Else, generate image and upload to storage. - const BACKGROUND = { - REG: { - BG: `${STORAGE_URL}/assets/backgrounds/regular.png`, - LOGO: `${STORAGE_URL}/assets/lw8-logo-regular.png`, - }, - GOLD: { - BG: `${STORAGE_URL}/assets/backgrounds/golden.png`, - LOGO: `${STORAGE_URL}/assets/lw8-logo-gold.png`, - }, - } - - const fontData = await font - const monoFontData = await mono_font - const numDigits = `${Number(ticketNumber)}`.length - const prefix = `00000000`.slice(numDigits) - const HAS_ROLE = !!metadata?.role - const HAS_COMPANY = !!metadata?.company - const HAS_LOCATION = !!metadata?.location - const HAS_NO_META = !HAS_ROLE && !HAS_COMPANY && !HAS_LOCATION - - const generatedTicketImage = new ImageResponse( - ( - <> -
    - {/* Background */} - -
    - -
    - - {/* Name & username */} -
    -
    -

    - {name ?? username} -

    -
    - - {/* Username */} -
    - {HAS_NO_META && username && `@${username}`} - {HAS_ROLE && `${metadata.role}`} - {HAS_COMPANY && `${HAS_ROLE ? ' at ' : ''}${metadata.company} `} - {HAS_LOCATION && `${(HAS_ROLE || HAS_COMPANY) && ' —'} ${metadata.location}`} -
    -
    -

    - August 7-11 - supabase.com/launch-week -

    -
    - {/* Ticket No */} -

    - {`NO ${prefix}${ticketNumber}`} -

    - - ), - { - width: 1200, - height: 628, - fonts: [ - { - name: 'Circular', - data: fontData, - style: 'normal', - }, - { - name: 'SourceCodePro', - data: monoFontData, - style: 'normal', - }, - ], - headers: { - 'content-type': 'image/png', - 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', - 'cdn-cache-control': 'max-age=31536000', - }, - } - ) - - // Upload image to storage. - const { error: storageError } = await supabaseAdminClient.storage - .from('images') - .upload( - `lw8/tickets/${golden ? 'golden' : 'regular'}/${BUCKET_FOLDER_VERSION}/${username}.png`, - generatedTicketImage.body!, - { - contentType: 'image/png', - // cacheControl: `${60 * 60 * 24 * 7}`, - cacheControl: `0`, - // Update cached og image, people might need to update info - upsert: true, - } - ) - if (storageError) throw new Error(`storageError: ${storageError.message}`) - - // Generate og image - fetch('https://obuldanrptloktxcffvn.supabase.co/functions/v1/lw8-ticket-og', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9idWxkYW5ycHRsb2t0eGNmZnZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTIyNjkzMjYsImV4cCI6MjAwNzg0NTMyNn0.1S6qpBbHtEmGuMsIx5UOhRiFd4YbVv-yLTrLk6tVGmM', - }, - body: JSON.stringify({ - username, - golden, - }), - }) - - return await fetch( - `${STORAGE_URL}/tickets/${ - golden ? 'golden' : 'regular' - }/${BUCKET_FOLDER_VERSION}/${username}.png` - ) - } catch (error) { - return new Response(JSON.stringify({ error: error.message }), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' }, - status: 400, - }) - } -} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index efa33dafd74..0a074290a57 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,7 +10,7 @@ version: "3.8" services: studio: container_name: supabase-studio - image: supabase/studio:20240301-0942bfe + image: supabase/studio:20240326-5e5586d restart: unless-stopped healthcheck: test: @@ -156,7 +156,7 @@ services: realtime: # This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain container_name: realtime-dev.supabase-realtime - image: supabase/realtime:v2.25.66 + image: supabase/realtime:v2.27.5 depends_on: db: # Disable this if you are using an external Postgres database @@ -274,7 +274,7 @@ services: functions: container_name: supabase-edge-functions - image: supabase/edge-runtime:v1.38.0 + image: supabase/edge-runtime:v1.41.2 restart: unless-stopped depends_on: analytics: diff --git a/examples/auth/nextjs/.env.example b/examples/auth/nextjs/.env.example new file mode 100644 index 00000000000..693703197a7 --- /dev/null +++ b/examples/auth/nextjs/.env.example @@ -0,0 +1,4 @@ +# Update these with your Supabase details from your project settings > API +# https://app.supabase.com/project/_/settings/api +NEXT_PUBLIC_SUPABASE_URL=your-project-url +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/examples/auth/nextjs/.env.local.example b/examples/auth/nextjs/.env.local.example deleted file mode 100644 index d762c758fbb..00000000000 --- a/examples/auth/nextjs/.env.local.example +++ /dev/null @@ -1,4 +0,0 @@ -# Get these from your API settings: https://supabase.com/dashboard/project/_/settings/api - -NEXT_PUBLIC_SUPABASE_URL=your-supabase-url -NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key diff --git a/examples/auth/nextjs/.eslintrc.json b/examples/auth/nextjs/.eslintrc.json deleted file mode 100644 index bffb357a712..00000000000 --- a/examples/auth/nextjs/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/examples/auth/nextjs/.gitignore b/examples/auth/nextjs/.gitignore index c87c9b392c0..fd3dbb571a1 100644 --- a/examples/auth/nextjs/.gitignore +++ b/examples/auth/nextjs/.gitignore @@ -4,6 +4,7 @@ /node_modules /.pnp .pnp.js +.yarn/install-state.gz # testing /coverage @@ -23,7 +24,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* # local env files .env*.local diff --git a/examples/auth/nextjs/README.md b/examples/auth/nextjs/README.md index cfecec8c159..9974f0c7625 100644 --- a/examples/auth/nextjs/README.md +++ b/examples/auth/nextjs/README.md @@ -1,38 +1,93 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + + Next.js and Supabase Starter Kit - the fastest way to build apps with Next.js and Supabase +

    Next.js and Supabase Starter Kit

    +
    -## Getting Started +

    + The fastest way to build apps with Next.js and Supabase +

    -First, run the development server: +

    + Features · + Demo · + Deploy to Vercel · + Clone and run locally · + Feedback and issues + More Examples +

    +
    -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -``` +## Features -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +- Works across the entire [Next.js](https://nextjs.org) stack + - App Router + - Pages Router + - Middleware + - Client + - Server + - It just works! +- supabase-ssr. A package to configure Supabase Auth to use cookies +- Styling with [Tailwind CSS](https://tailwindcss.com) +- Optional deployment with [Supabase Vercel Integration and Vercel deploy](#deploy-your-own) + - Environment variables automatically assigned to Vercel project -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +## Demo -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `app/api/hello.ts`. +You can view a fully working demo at [demo-nextjs-with-supabase.vercel.app](https://demo-nextjs-with-supabase.vercel.app/). -The `app/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. +## Deploy to Vercel -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. +Vercel deployment will guide you through creating a Supabase account and project. -## Learn More +After installation of the Supabase integration, all relevant environment variables will be assigned to the project so the deployment is fully functioning. -To learn more about Next.js, take a look at the following resources: +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&project-name=nextjs-with-supabase&repository-name=nextjs-with-supabase&demo-title=nextjs-with-supabase&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2Fopengraph-image.png&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6) -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +The above will also clone the Starter kit to your GitHub, you can clone that locally and develop locally. -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! +If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#clone-and-run-locally). -## Deploy on Vercel +## Clone and run locally -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +1. You'll first need a Supabase project which can be made [via the Supabase dashboard](https://database.new) -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +2. Create a Next.js app using the Supabase Starter template npx command + + ```bash + npx create-next-app -e with-supabase + ``` + +3. Use `cd` to change into the app's directory + + ```bash + cd name-of-new-app + ``` + +4. Rename `.env.local.example` to `.env.local` and update the following: + + ``` + NEXT_PUBLIC_SUPABASE_URL=[INSERT SUPABASE PROJECT URL] + NEXT_PUBLIC_SUPABASE_ANON_KEY=[INSERT SUPABASE PROJECT API ANON KEY] + ``` + + Both `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` can be found in [your Supabase project's API settings](https://app.supabase.com/project/_/settings/api) + +5. You can now run the Next.js local development server: + + ```bash + npm run dev + ``` + + The starter kit should now be running on [localhost:3000](http://localhost:3000/). + +> Check out [the docs for Local Development](https://supabase.com/docs/guides/getting-started/local-development) to also run Supabase locally. + +## Feedback and issues + +Please file feedback and issues over on the [Supabase GitHub org](https://github.com/supabase/supabase/issues/new/choose). + +## More Supabase examples + +- [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments) +- [Cookie-based Auth and the Next.js 13 App Router (free course)](https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF) +- [Supabase Auth and the Next.js App Router](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs) diff --git a/examples/auth/nextjs/app/[id]/page.tsx b/examples/auth/nextjs/app/[id]/page.tsx deleted file mode 100644 index e06effa3fed..00000000000 --- a/examples/auth/nextjs/app/[id]/page.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' -import { notFound, redirect } from 'next/navigation' -import RealtimePost from './realtime-post' -import { cookies } from 'next/headers' - -import type { Database } from '@/lib/database.types' - -export default async function Post({ params: { id } }: { params: { id: string } }) { - const supabase = createServerComponentClient({ - cookies, - }) - - const { - data: { session }, - } = await supabase.auth.getSession() - - if (!session) { - // this is a protected route - only users who are signed in can view this route - redirect('/') - } - - const { data: post } = await supabase.from('posts').select().match({ id }).single() - - if (!post) { - notFound() - } - - return -} diff --git a/examples/auth/nextjs/app/[id]/realtime-post.tsx b/examples/auth/nextjs/app/[id]/realtime-post.tsx deleted file mode 100644 index 8591020db48..00000000000 --- a/examples/auth/nextjs/app/[id]/realtime-post.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' -import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' - -import type { Database } from '@/lib/database.types' - -type Post = Database['public']['Tables']['posts']['Row'] - -export default function RealtimePost({ serverPost }: { serverPost: Post }) { - const supabase = createClientComponentClient() - const [post, setPost] = useState(serverPost) - - useEffect(() => { - setPost(serverPost) - }, [serverPost]) - - useEffect(() => { - const channel = supabase - .channel('realtime post') - .on( - 'postgres_changes', - { - event: 'UPDATE', - schema: 'public', - table: 'posts', - filter: `id=eq.${post.id}`, - }, - (payload) => { - setPost(payload.new as Post) - } - ) - .subscribe() - - return () => { - supabase.removeChannel(channel) - } - }, [supabase, post, setPost]) - - return
    {JSON.stringify(post, null, 2)}
    -} diff --git a/examples/auth/nextjs/app/auth/callback/route.ts b/examples/auth/nextjs/app/auth/callback/route.ts index 3ce586204ac..b3877c6516a 100644 --- a/examples/auth/nextjs/app/auth/callback/route.ts +++ b/examples/auth/nextjs/app/auth/callback/route.ts @@ -1,18 +1,19 @@ -import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' -import { cookies } from 'next/headers' -import { NextResponse } from 'next/server' - -import type { Database } from '@/lib/database.types' +import { createClient } from "@/utils/supabase/server"; +import { NextResponse } from "next/server"; export async function GET(request: Request) { - const requestUrl = new URL(request.url) - const code = requestUrl.searchParams.get('code') + // The `/auth/callback` route is required for the server-side auth flow implemented + // by the SSR package. It exchanges an auth code for the user's session. + // https://supabase.com/docs/guides/auth/server-side/nextjs + const requestUrl = new URL(request.url); + const code = requestUrl.searchParams.get("code"); + const origin = requestUrl.origin; if (code) { - const supabase = createRouteHandlerClient({ cookies }) - await supabase.auth.exchangeCodeForSession(code) + const supabase = createClient(); + await supabase.auth.exchangeCodeForSession(code); } - // URL to redirect to after sign in process completes - return NextResponse.redirect(requestUrl.origin) + // URL to redirect to after sign up process completes + return NextResponse.redirect(`${origin}/protected`); } diff --git a/examples/auth/nextjs/app/globals.css b/examples/auth/nextjs/app/globals.css index d4f491e152d..50bd9fc3356 100644 --- a/examples/auth/nextjs/app/globals.css +++ b/examples/auth/nextjs/app/globals.css @@ -1,107 +1,42 @@ -:root { - --max-width: 1100px; - --border-radius: 12px; - --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', - 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', - 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; +@tailwind base; +@tailwind components; +@tailwind utilities; - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; - - --primary-glow: conic-gradient( - from 180deg at 50% 50%, - #16abff33 0deg, - #0885ff33 55deg, - #54d6ff33 120deg, - #0071ff33 160deg, - transparent 360deg - ); - --secondary-glow: radial-gradient( - rgba(255, 255, 255, 1), - rgba(255, 255, 255, 0) - ); - - --tile-start-rgb: 239, 245, 249; - --tile-end-rgb: 228, 232, 233; - --tile-border: conic-gradient( - #00000080, - #00000040, - #00000030, - #00000020, - #00000010, - #00000010, - #00000080 - ); - - --callout-rgb: 238, 240, 241; - --callout-border-rgb: 172, 175, 176; - --card-rgb: 180, 185, 188; - --card-border-rgb: 131, 134, 135; -} - -@media (prefers-color-scheme: dark) { +@layer base { :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; + --background: 200 20% 98%; + --btn-background: 200 10% 91%; + --btn-background-hover: 200 10% 89%; + --foreground: 200 50% 3%; + } - --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); - --secondary-glow: linear-gradient( - to bottom right, - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0.3) - ); - - --tile-start-rgb: 2, 13, 46; - --tile-end-rgb: 2, 5, 19; - --tile-border: conic-gradient( - #ffffff80, - #ffffff40, - #ffffff30, - #ffffff20, - #ffffff10, - #ffffff10, - #ffffff80 - ); - - --callout-rgb: 20, 20, 20; - --callout-border-rgb: 108, 108, 108; - --card-rgb: 100, 100, 100; - --card-border-rgb: 200, 200, 200; + @media (prefers-color-scheme: dark) { + :root { + --background: 200 50% 3%; + --btn-background: 200 10% 9%; + --btn-background-hover: 200 10% 12%; + --foreground: 200 20% 96%; + } } } -* { - box-sizing: border-box; - padding: 0; - margin: 0; +@layer base { + * { + @apply border-foreground/20; + } } -html, -body { - max-width: 100vw; - overflow-x: hidden; +.animate-in { + animation: animateIn 0.3s ease 0.15s both; } -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; +@keyframes animateIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); } } diff --git a/examples/auth/nextjs/app/layout.tsx b/examples/auth/nextjs/app/layout.tsx index 7604edfa291..39e5666f260 100644 --- a/examples/auth/nextjs/app/layout.tsx +++ b/examples/auth/nextjs/app/layout.tsx @@ -1,19 +1,28 @@ -import './globals.css' -import Login from './login' +import { GeistSans } from "geist/font/sans"; +import "./globals.css"; + +const defaultUrl = process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : "http://localhost:3000"; export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} + metadataBase: new URL(defaultUrl), + title: "Next.js and Supabase Starter Kit", + description: "The fastest way to build apps with Next.js and Supabase", +}; -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { return ( - - - {/* @ts-expect-error next version of TS will fix this */} - - {children} + + +
    + {children} +
    - ) + ); } diff --git a/examples/auth/nextjs/app/login-form.tsx b/examples/auth/nextjs/app/login-form.tsx deleted file mode 100644 index dd5b9db0357..00000000000 --- a/examples/auth/nextjs/app/login-form.tsx +++ /dev/null @@ -1,56 +0,0 @@ -'use client' - -import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' -import { useRouter } from 'next/navigation' -import { useState } from 'react' - -import type { Session } from '@supabase/auth-helpers-nextjs' - -export default function LoginForm({ session }: { session: Session | null }) { - const [email, setEmail] = useState('') - const [password, setPassword] = useState('') - const router = useRouter() - const supabase = createClientComponentClient() - - const handleSignUp = async () => { - await supabase.auth.signUp({ - email, - password, - options: { - emailRedirectTo: `${location.origin}/auth/callback`, - }, - }) - router.refresh() - } - - const handleSignIn = async () => { - await supabase.auth.signInWithPassword({ - email, - password, - }) - router.refresh() - } - - const handleSignOut = async () => { - await supabase.auth.signOut() - router.refresh() - } - - // for the `session` to be available on first SSR render, it must be - // fetched in a Server Component and passed down as a prop - return session ? ( - - ) : ( - <> - setEmail(e.target.value)} value={email} /> - setPassword(e.target.value)} - value={password} - /> - - - - ) -} diff --git a/examples/auth/nextjs/app/login.tsx b/examples/auth/nextjs/app/login.tsx deleted file mode 100644 index 3d7eca84734..00000000000 --- a/examples/auth/nextjs/app/login.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' -import { cookies } from 'next/headers' -import LoginForm from './login-form' - -import type { Database } from '@/lib/database.types' - -export default async function Login() { - const supabase = createServerComponentClient({ cookies }) - - const { - data: { session }, - } = await supabase.auth.getSession() - - return -} diff --git a/examples/auth/nextjs/app/login/page.tsx b/examples/auth/nextjs/app/login/page.tsx new file mode 100644 index 00000000000..7358f05420d --- /dev/null +++ b/examples/auth/nextjs/app/login/page.tsx @@ -0,0 +1,119 @@ +import Link from "next/link"; +import { headers } from "next/headers"; +import { createClient } from "@/utils/supabase/server"; +import { redirect } from "next/navigation"; +import { SubmitButton } from "./submit-button"; + +export default function Login({ + searchParams, +}: { + searchParams: { message: string }; +}) { + const signIn = async (formData: FormData) => { + "use server"; + + const email = formData.get("email") as string; + const password = formData.get("password") as string; + const supabase = createClient(); + + const { error } = await supabase.auth.signInWithPassword({ + email, + password, + }); + + if (error) { + return redirect("/login?message=Could not authenticate user"); + } + + return redirect("/protected"); + }; + + const signUp = async (formData: FormData) => { + "use server"; + + const origin = headers().get("origin"); + const email = formData.get("email") as string; + const password = formData.get("password") as string; + const supabase = createClient(); + + const { error } = await supabase.auth.signUp({ + email, + password, + options: { + emailRedirectTo: `${origin}/auth/callback`, + }, + }); + + if (error) { + return redirect("/login?message=Could not authenticate user"); + } + + return redirect("/login?message=Check email to continue sign in process"); + }; + + return ( +
    + + + + {" "} + Back + + +
    + + + + + + Sign In + + + Sign Up + + {searchParams?.message && ( +

    + {searchParams.message} +

    + )} + +
    + ); +} diff --git a/examples/auth/nextjs/app/login/submit-button.tsx b/examples/auth/nextjs/app/login/submit-button.tsx new file mode 100644 index 00000000000..9d8553358db --- /dev/null +++ b/examples/auth/nextjs/app/login/submit-button.tsx @@ -0,0 +1,20 @@ +"use client"; + +import { useFormStatus } from "react-dom"; +import { type ComponentProps } from "react"; + +type Props = ComponentProps<"button"> & { + pendingText?: string; +}; + +export function SubmitButton({ children, pendingText, ...props }: Props) { + const { pending, action } = useFormStatus(); + + const isPending = pending && action === props.formAction; + + return ( + + ); +} diff --git a/examples/auth/nextjs/app/new-post.tsx b/examples/auth/nextjs/app/new-post.tsx deleted file mode 100644 index c28caddbbab..00000000000 --- a/examples/auth/nextjs/app/new-post.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createServerActionClient } from '@supabase/auth-helpers-nextjs' -import { revalidatePath } from 'next/cache' -import { cookies } from 'next/headers' - -import type { Database } from '@/lib/database.types' - -export default function NewPost() { - const addPost = async (formData: FormData) => { - 'use server' - const content = String(formData.get('content')) - const supabase = createServerActionClient({ cookies }) - await supabase.from('posts').insert({ content }).select() - revalidatePath('/') - } - - return ( -
    - - - ) -} diff --git a/examples/auth/nextjs/app/opengraph-image.png b/examples/auth/nextjs/app/opengraph-image.png new file mode 100644 index 00000000000..57595e662c3 Binary files /dev/null and b/examples/auth/nextjs/app/opengraph-image.png differ diff --git a/examples/auth/nextjs/app/page.module.css b/examples/auth/nextjs/app/page.module.css deleted file mode 100644 index 4732b55fdc2..00000000000 --- a/examples/auth/nextjs/app/page.module.css +++ /dev/null @@ -1,271 +0,0 @@ -.main { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - padding: 6rem; - min-height: 100vh; -} - -.description { - display: inherit; - justify-content: inherit; - align-items: inherit; - font-size: 0.85rem; - max-width: var(--max-width); - width: 100%; - z-index: 2; - font-family: var(--font-mono); -} - -.description a { - display: flex; - align-items: center; - justify-content: center; - gap: 0.5rem; -} - -.description p { - position: relative; - margin: 0; - padding: 1rem; - background-color: rgba(var(--callout-rgb), 0.5); - border: 1px solid rgba(var(--callout-border-rgb), 0.3); - border-radius: var(--border-radius); -} - -.code { - font-weight: 700; - font-family: var(--font-mono); -} - -.grid { - display: grid; - grid-template-columns: repeat(3, minmax(33%, auto)); - width: var(--max-width); - max-width: 100%; -} - -.card { - padding: 1rem 1.2rem; - border-radius: var(--border-radius); - background: rgba(var(--card-rgb), 0); - border: 1px solid rgba(var(--card-border-rgb), 0); - transition: background 200ms, border 200ms; -} - -.card span { - display: inline-block; - transition: transform 200ms; -} - -.card h2 { - font-weight: 600; - margin-bottom: 0.7rem; -} - -.card p { - margin: 0; - opacity: 0.6; - font-size: 0.9rem; - line-height: 1.5; - max-width: 34ch; -} - -.center { - display: flex; - justify-content: center; - align-items: center; - position: relative; - padding: 4rem 0; -} - -.center::before { - background: var(--secondary-glow); - border-radius: 50%; - width: 480px; - height: 360px; - margin-left: -400px; -} - -.center::after { - background: var(--primary-glow); - width: 240px; - height: 180px; - z-index: -1; -} - -.center::before, -.center::after { - content: ''; - left: 50%; - position: absolute; - filter: blur(45px); - transform: translateZ(0); -} - -.logo, -.thirteen { - position: relative; -} - -.thirteen { - display: flex; - justify-content: center; - align-items: center; - width: 75px; - height: 75px; - padding: 25px 10px; - margin-left: 16px; - transform: translateZ(0); - border-radius: var(--border-radius); - overflow: hidden; - box-shadow: 0px 2px 8px -1px #0000001a; -} - -.thirteen::before, -.thirteen::after { - content: ''; - position: absolute; - z-index: -1; -} - -/* Conic Gradient Animation */ -.thirteen::before { - animation: 6s rotate linear infinite; - width: 200%; - height: 200%; - background: var(--tile-border); -} - -/* Inner Square */ -.thirteen::after { - inset: 0; - padding: 1px; - border-radius: var(--border-radius); - background: linear-gradient( - to bottom right, - rgba(var(--tile-start-rgb), 1), - rgba(var(--tile-end-rgb), 1) - ); - background-clip: content-box; -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - .card:hover { - background: rgba(var(--card-rgb), 0.1); - border: 1px solid rgba(var(--card-border-rgb), 0.15); - } - - .card:hover span { - transform: translateX(4px); - } -} - -@media (prefers-reduced-motion) { - .thirteen::before { - animation: none; - } - - .card:hover span { - transform: none; - } -} - -/* Mobile and Tablet */ -@media (max-width: 1023px) { - .content { - padding: 4rem; - } - - .grid { - grid-template-columns: 1fr; - margin-bottom: 120px; - max-width: 320px; - text-align: center; - } - - .card { - padding: 1rem 2.5rem; - } - - .card h2 { - margin-bottom: 0.5rem; - } - - .center { - padding: 8rem 0 6rem; - } - - .center::before { - transform: none; - height: 300px; - } - - .description { - font-size: 0.8rem; - } - - .description a { - padding: 1rem; - } - - .description p, - .description div { - display: flex; - justify-content: center; - position: fixed; - width: 100%; - } - - .description p { - align-items: center; - inset: 0 0 auto; - padding: 2rem 1rem 1.4rem; - border-radius: 0; - border: none; - border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); - background: linear-gradient( - to bottom, - rgba(var(--background-start-rgb), 1), - rgba(var(--callout-rgb), 0.5) - ); - background-clip: padding-box; - backdrop-filter: blur(24px); - } - - .description div { - align-items: flex-end; - pointer-events: none; - inset: auto 0 0; - padding: 2rem; - height: 200px; - background: linear-gradient( - to bottom, - transparent 0%, - rgb(var(--background-end-rgb)) 40% - ); - z-index: 1; - } -} - -@media (prefers-color-scheme: dark) { - .vercelLogo { - filter: invert(1); - } - - .logo, - .thirteen img { - filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); - } -} - -@keyframes rotate { - from { - transform: rotate(360deg); - } - to { - transform: rotate(0deg); - } -} diff --git a/examples/auth/nextjs/app/page.tsx b/examples/auth/nextjs/app/page.tsx index 1efe4e8e4c7..1881cc13f0f 100644 --- a/examples/auth/nextjs/app/page.tsx +++ b/examples/auth/nextjs/app/page.tsx @@ -1,20 +1,54 @@ -import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' -import { cookies } from 'next/headers' -import RealtimePosts from './realtime-posts' -import NewPost from './new-post' +import DeployButton from "../components/DeployButton"; +import AuthButton from "../components/AuthButton"; +import { createClient } from "@/utils/supabase/server"; +import ConnectSupabaseSteps from "@/components/tutorial/ConnectSupabaseSteps"; +import SignUpUserSteps from "@/components/tutorial/SignUpUserSteps"; +import Header from "@/components/Header"; -import type { Database } from '@/lib/database.types' +export default async function Index() { + const canInitSupabaseClient = () => { + // This function is just for the interactive tutorial. + // Feel free to remove it once you have Supabase connected. + try { + createClient(); + return true; + } catch (e) { + return false; + } + }; -export default async function ServerComponent() { - const supabase = createServerComponentClient({ - cookies, - }) - const { data } = await supabase.from('posts').select('*') + const isSupabaseConnected = canInitSupabaseClient(); return ( - <> - - - - ) +
    + + +
    +
    +
    +

    Next steps

    + {isSupabaseConnected ? : } +
    +
    + + +
    + ); } diff --git a/examples/auth/nextjs/app/protected/page.tsx b/examples/auth/nextjs/app/protected/page.tsx new file mode 100644 index 00000000000..1d73e55118b --- /dev/null +++ b/examples/auth/nextjs/app/protected/page.tsx @@ -0,0 +1,57 @@ +import DeployButton from "@/components/DeployButton"; +import AuthButton from "@/components/AuthButton"; +import { createClient } from "@/utils/supabase/server"; +import FetchDataSteps from "@/components/tutorial/FetchDataSteps"; +import Header from "@/components/Header"; +import { redirect } from "next/navigation"; + +export default async function ProtectedPage() { + const supabase = createClient(); + + const { + data: { user }, + } = await supabase.auth.getUser(); + + if (!user) { + return redirect("/login"); + } + + return ( +
    +
    +
    + This is a protected page that you can only see as an authenticated + user +
    + +
    + +
    +
    +
    +

    Next steps

    + +
    +
    + + +
    + ); +} diff --git a/examples/auth/nextjs/app/realtime-posts.tsx b/examples/auth/nextjs/app/realtime-posts.tsx deleted file mode 100644 index 4755da7fefc..00000000000 --- a/examples/auth/nextjs/app/realtime-posts.tsx +++ /dev/null @@ -1,40 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' -import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' - -import type { Database } from '@/lib/database.types' -import Link from 'next/link' -type Post = Database['public']['Tables']['posts']['Row'] - -export default function RealtimePosts({ serverPosts }: { serverPosts: Post[] }) { - const [posts, setPosts] = useState(serverPosts) - const supabase = createClientComponentClient() - - useEffect(() => { - setPosts(serverPosts) - }, [serverPosts]) - - useEffect(() => { - const channel = supabase - .channel('*') - .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' }, (payload) => - setPosts((posts) => [...posts, payload.new as Post]) - ) - .subscribe() - - return () => { - supabase.removeChannel(channel) - } - }, [supabase, setPosts, posts]) - - return ( - <> - {posts.map((post) => ( -
    - {post.content} -
    - ))} - - ) -} diff --git a/examples/auth/nextjs/app/sitemap.ts b/examples/auth/nextjs/app/sitemap.ts deleted file mode 100644 index d1c0e8a40c6..00000000000 --- a/examples/auth/nextjs/app/sitemap.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' -import { cookies } from 'next/headers' - -export default async function sitemap() { - const supabase = createServerComponentClient({ cookies }) - const { data: posts } = await supabase.from('posts').select() - - return ( - posts?.map(({ id }) => ({ - url: `https://example.com/${id}`, - lastModified: new Date(), - })) ?? [] - ) -} diff --git a/examples/auth/nextjs/app/twitter-image.png b/examples/auth/nextjs/app/twitter-image.png new file mode 100644 index 00000000000..57595e662c3 Binary files /dev/null and b/examples/auth/nextjs/app/twitter-image.png differ diff --git a/examples/auth/nextjs/components/AuthButton.tsx b/examples/auth/nextjs/components/AuthButton.tsx new file mode 100644 index 00000000000..8970bd7946e --- /dev/null +++ b/examples/auth/nextjs/components/AuthButton.tsx @@ -0,0 +1,37 @@ +import { createClient } from "@/utils/supabase/server"; +import Link from "next/link"; +import { redirect } from "next/navigation"; + +export default async function AuthButton() { + const supabase = createClient(); + + const { + data: { user }, + } = await supabase.auth.getUser(); + + const signOut = async () => { + "use server"; + + const supabase = createClient(); + await supabase.auth.signOut(); + return redirect("/login"); + }; + + return user ? ( +
    + Hey, {user.email}! +
    + + +
    + ) : ( + + Login + + ); +} diff --git a/examples/auth/nextjs/components/DeployButton.tsx b/examples/auth/nextjs/components/DeployButton.tsx new file mode 100644 index 00000000000..c46d23f4fd7 --- /dev/null +++ b/examples/auth/nextjs/components/DeployButton.tsx @@ -0,0 +1,23 @@ +export default function DeployButton() { + return ( + + + + + Deploy to Vercel + + ); +} diff --git a/examples/auth/nextjs/components/Header.tsx b/examples/auth/nextjs/components/Header.tsx new file mode 100644 index 00000000000..9996d5d106c --- /dev/null +++ b/examples/auth/nextjs/components/Header.tsx @@ -0,0 +1,44 @@ +import NextLogo from "./NextLogo"; +import SupabaseLogo from "./SupabaseLogo"; + +export default function Header() { + return ( +
    +
    + + + + + + + +
    +

    Supabase and Next.js Starter Template

    +

    + The fastest way to build apps with{" "} + + Supabase + {" "} + and{" "} + + Next.js + +

    +
    +
    + ); +} diff --git a/examples/auth/nextjs/components/NextLogo.tsx b/examples/auth/nextjs/components/NextLogo.tsx new file mode 100644 index 00000000000..16555821326 --- /dev/null +++ b/examples/auth/nextjs/components/NextLogo.tsx @@ -0,0 +1,46 @@ +export default function NextLogo() { + return ( + + + + + + + + + + + ); +} diff --git a/examples/auth/nextjs/components/SupabaseLogo.tsx b/examples/auth/nextjs/components/SupabaseLogo.tsx new file mode 100644 index 00000000000..96a56a54ac7 --- /dev/null +++ b/examples/auth/nextjs/components/SupabaseLogo.tsx @@ -0,0 +1,102 @@ +export default function SupabaseLogo() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/examples/auth/nextjs/components/tutorial/Code.tsx b/examples/auth/nextjs/components/tutorial/Code.tsx new file mode 100644 index 00000000000..f96d0cf7749 --- /dev/null +++ b/examples/auth/nextjs/components/tutorial/Code.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { useState } from "react"; + +const CopyIcon = () => ( + + + + +); + +const CheckIcon = () => ( + + + +); + +export default function Code({ code }: { code: string }) { + const [icon, setIcon] = useState(CopyIcon); + + const copy = async () => { + await navigator?.clipboard?.writeText(code); + setIcon(CheckIcon); + setTimeout(() => setIcon(CopyIcon), 2000); + }; + + return ( +
    +      
    +      {code}
    +    
    + ); +} diff --git a/examples/auth/nextjs/components/tutorial/ConnectSupabaseSteps.tsx b/examples/auth/nextjs/components/tutorial/ConnectSupabaseSteps.tsx new file mode 100644 index 00000000000..0493b8d246a --- /dev/null +++ b/examples/auth/nextjs/components/tutorial/ConnectSupabaseSteps.tsx @@ -0,0 +1,62 @@ +import Step from "./Step"; + +export default function ConnectSupabaseSteps() { + return ( +
      + +

      + Head over to{" "} + + database.new + {" "} + and create a new Supabase project. +

      +
      + + +

      + Rename the{" "} + + .env.example + {" "} + file in your Next.js app to{" "} + + .env.local + {" "} + and populate with values from{" "} + + your Supabase project's API Settings + + . +

      +
      + + +

      + You may need to quit your Next.js development server and run{" "} + + npm run dev + {" "} + again to load the new environment variables. +

      +
      + + +

      + You may need to refresh the page for Next.js to load the new + environment variables. +

      +
      +
    + ); +} diff --git a/examples/auth/nextjs/components/tutorial/FetchDataSteps.tsx b/examples/auth/nextjs/components/tutorial/FetchDataSteps.tsx new file mode 100644 index 00000000000..0099f8e155c --- /dev/null +++ b/examples/auth/nextjs/components/tutorial/FetchDataSteps.tsx @@ -0,0 +1,99 @@ +import Step from "./Step"; +import Code from "./Code"; + +const create = ` +create table notes ( + id bigserial primary key, + title text +); + +insert into notes(title) +values + ('Today I created a Supabase project.'), + ('I added some data and queried it from Next.js.'), + ('It was awesome!'); +`.trim(); + +const server = ` +import { createClient } from '@/utils/supabase/server' + +export default async function Page() { + const supabase = createClient() + const { data: notes } = await supabase.from('notes').select() + + return
    {JSON.stringify(notes, null, 2)}
    +} +`.trim(); + +const client = ` +'use client' + +import { createClient } from '@/utils/supabase/client' +import { useEffect, useState } from 'react' + +export default function Page() { + const [notes, setNotes] = useState(null) + const supabase = createClient() + + useEffect(() => { + const getData = async () => { + const { data } = await supabase.from('notes').select() + setNotes(data) + } + getData() + }, []) + + return
    {JSON.stringify(notes, null, 2)}
    +} +`.trim(); + +export default function FetchDataSteps() { + return ( +
      + +

      + Head over to the{" "} + + Table Editor + {" "} + for your Supabase project to create a table and insert some example + data. If you're stuck for creativity, you can copy and paste the + following into the{" "} + + SQL Editor + {" "} + and click RUN! +

      + +
      + + +

      + To create a Supabase client and query data from an Async Server + Component, create a new page.tsx file at{" "} + + /app/notes/page.tsx + {" "} + and add the following. +

      + +

      Alternatively, you can use a Client Component.

      + +
      + + +

      You're ready to launch your product to the world! 🚀

      +
      +
    + ); +} diff --git a/examples/auth/nextjs/components/tutorial/SignUpUserSteps.tsx b/examples/auth/nextjs/components/tutorial/SignUpUserSteps.tsx new file mode 100644 index 00000000000..6af78a08ddd --- /dev/null +++ b/examples/auth/nextjs/components/tutorial/SignUpUserSteps.tsx @@ -0,0 +1,22 @@ +import Link from "next/link"; +import Step from "./Step"; + +export default function SignUpUserSteps() { + return ( +
      + +

      + Head over to the{" "} + + Login + {" "} + page and sign up your first user. It's okay if this is just you for + now. Your awesome idea will have plenty of users later! +

      +
      +
    + ); +} diff --git a/examples/auth/nextjs/components/tutorial/Step.tsx b/examples/auth/nextjs/components/tutorial/Step.tsx new file mode 100644 index 00000000000..cad86cf30ac --- /dev/null +++ b/examples/auth/nextjs/components/tutorial/Step.tsx @@ -0,0 +1,24 @@ +export default function Step({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) { + return ( +
  • + + +
    + {children} +
    +
  • + ); +} diff --git a/examples/auth/nextjs/lib/database.types.ts b/examples/auth/nextjs/lib/database.types.ts deleted file mode 100644 index 0f174b0913e..00000000000 --- a/examples/auth/nextjs/lib/database.types.ts +++ /dev/null @@ -1,46 +0,0 @@ -export type Json = - | string - | number - | boolean - | null - | { [key: string]: Json } - | Json[]; - -export interface Database { - public: { - Tables: { - posts: { - Row: { - content: string; - created_at: string; - id: number; - user_id: string | null; - }; - Insert: { - content: string; - created_at?: string; - id?: number; - user_id?: string | null; - }; - Update: { - content?: string; - created_at?: string; - id?: number; - user_id?: string | null; - }; - }; - }; - Views: { - [_ in never]: never; - }; - Functions: { - [_ in never]: never; - }; - Enums: { - [_ in never]: never; - }; - CompositeTypes: { - [_ in never]: never; - }; - }; -} diff --git a/examples/auth/nextjs/middleware.ts b/examples/auth/nextjs/middleware.ts index 71bd069a484..53428f8c9a7 100644 --- a/examples/auth/nextjs/middleware.ts +++ b/examples/auth/nextjs/middleware.ts @@ -1,12 +1,20 @@ -import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' -import { NextResponse } from 'next/server' +import { type NextRequest } from "next/server"; +import { updateSession } from "@/utils/supabase/middleware"; -import type { NextRequest } from 'next/server' -import type { Database } from '@/lib/database.types' - -export async function middleware(req: NextRequest) { - const res = NextResponse.next() - const supabase = createMiddlewareClient({ req, res }) - await supabase.auth.getSession() - return res +export async function middleware(request: NextRequest) { + return await updateSession(request); } + +export const config = { + matcher: [ + /* + * Match all request paths except: + * - _next/static (static files) + * - _next/image (image optimization files) + * - favicon.ico (favicon file) + * - images - .svg, .png, .jpg, .jpeg, .gif, .webp + * Feel free to modify this pattern to include more paths. + */ + "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", + ], +}; diff --git a/examples/auth/nextjs/next.config.js b/examples/auth/nextjs/next.config.js index 950e2f42ec3..658404ac690 100644 --- a/examples/auth/nextjs/next.config.js +++ b/examples/auth/nextjs/next.config.js @@ -1,8 +1,4 @@ /** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - serverActions: true, - }, -} +const nextConfig = {}; -module.exports = nextConfig +module.exports = nextConfig; diff --git a/examples/auth/nextjs/package-lock.json b/examples/auth/nextjs/package-lock.json index a50bed53741..e9c5b085dfc 100644 --- a/examples/auth/nextjs/package-lock.json +++ b/examples/auth/nextjs/package-lock.json @@ -1,140 +1,107 @@ { - "name": "full-nextjs-auth-helpers", - "version": "0.1.0", - "lockfileVersion": 2, + "name": "nextjs", + "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "full-nextjs-auth-helpers", - "version": "0.1.0", "dependencies": { - "@supabase/auth-helpers-nextjs": "^0.7.1", - "@supabase/supabase-js": "^2.26.0", - "@types/node": "^20.2.3", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", - "eslint": "^8.41.0", - "next": "^13.4.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "typescript": "^5.0.4" + "@supabase/ssr": "latest", + "@supabase/supabase-js": "latest", + "autoprefixer": "10.4.17", + "geist": "^1.2.1", + "next": "latest", + "postcss": "8.4.33", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwindcss": "3.4.1", + "typescript": "5.3.3" }, "devDependencies": { - "eslint-config-next": "^13.4.3" + "@types/node": "20.11.5", + "@types/react": "18.2.48", + "@types/react-dom": "18.2.18", + "encoding": "^0.1.13" } }, - "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=12" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "engines": { - "node": ">=12.22" + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, "node_modules/@next/env": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", - "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" - }, - "node_modules/@next/eslint-plugin-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.3.tgz", - "integrity": "sha512-5B0uOnh7wyUY9vNNdIA6NUvWozhrZaTMZOzdirYAefqD0ZBK5C/h3+KMYdCKrR7JrXGvVpWnHtv54b3dCzwICA==", - "dev": true, - "dependencies": { - "glob": "7.1.7" - } + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", + "integrity": "sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==" }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", - "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.4.tgz", + "integrity": "sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==", "cpu": [ "arm64" ], @@ -147,9 +114,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", - "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", + "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", "cpu": [ "x64" ], @@ -162,9 +129,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", - "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", + "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", "cpu": [ "arm64" ], @@ -177,9 +144,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", - "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", + "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", "cpu": [ "arm64" ], @@ -192,9 +159,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", - "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", + "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", "cpu": [ "x64" ], @@ -207,9 +174,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", - "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", + "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", "cpu": [ "x64" ], @@ -222,9 +189,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", - "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", + "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", "cpu": [ "arm64" ], @@ -237,9 +204,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", - "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", + "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", "cpu": [ "ia32" ], @@ -252,9 +219,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", - "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", + "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", "cpu": [ "x64" ], @@ -298,143 +265,126 @@ "node": ">= 8" } }, - "node_modules/@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": ">=14" } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "node_modules/@supabase/auth-helpers-nextjs": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.7.2.tgz", - "integrity": "sha512-n5IyGBYJV/WiR5Rgw4CUaiJYiOv9yW2of4ZP4EyzKt2O6/6rztt7PcGE4AoK2vERw+fb5F2QtJBdt6J5eOYCCw==", + "node_modules/@supabase/auth-js": { + "version": "2.63.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.63.0.tgz", + "integrity": "sha512-yIgcHnlgv24GxHtVGUhwGqAFDyJkPIC/xjx7HostN08A8yCy8HIfl4JEkTKyBqD1v1L05jNEJOUke4Lf4O1+Qg==", "dependencies": { - "@supabase/auth-helpers-shared": "0.4.1", - "set-cookie-parser": "^2.6.0" - }, - "peerDependencies": { - "@supabase/supabase-js": "^2.19.0" - } - }, - "node_modules/@supabase/auth-helpers-shared": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.4.1.tgz", - "integrity": "sha512-IEDX9JzWkIjQiLUaP4Qy5YDiG0jFQatWfS+jw8cCQs6QfbNdEPd2Y3qonwGHnM90CZom9SvjuylBv2pFVAL7Lw==", - "dependencies": { - "jose": "^4.14.3" - }, - "peerDependencies": { - "@supabase/supabase-js": "^2.19.0" + "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/functions-js": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.1.2.tgz", - "integrity": "sha512-QCR6pwJs9exCl37bmpMisUd6mf+0SUBJ6mUpiAjEkSJ/+xW8TCuO14bvkWHADd5hElJK9MxNlMQXxSA4DRz9nQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.2.2.tgz", + "integrity": "sha512-sJGq1nludmi7pY/fdtCpyY/pYonx7MfHdN408bqb736guWcVI1AChYVbI4kUM978EuOE4Ci6l7bUudfGg07QRw==", "dependencies": { - "cross-fetch": "^3.1.5" + "@supabase/node-fetch": "^2.6.14" } }, - "node_modules/@supabase/gotrue-js": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.31.0.tgz", - "integrity": "sha512-YcwlbbNfedlue/HVIXtYBb4fuOrs29gNOTl6AmyxPp4zryRxzFvslVN9kmLDBRUAVU9fnPJh2bgOR3chRjJX5w==", + "node_modules/@supabase/node-fetch": { + "version": "2.6.15", + "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", + "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", "dependencies": { - "cross-fetch": "^3.1.5" + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" } }, "node_modules/@supabase/postgrest-js": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.7.1.tgz", - "integrity": "sha512-xPRYLaZrkLbXNlzmHW6Wtf9hmcBLjjI5xUz2zj8oE2hgXGaYoZBBkpN9bmW9i17Z1f6Ujxa942AqK439XOA36A==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.15.0.tgz", + "integrity": "sha512-U4bwBOrhsXWqDjZiYNbVqMBtRGgIIYE0kE5ZNSwsIbeBWfr/UxOMrnkIQUBGIZRhpYW/tw1WnTdRl1AGNyaxcw==", "dependencies": { - "cross-fetch": "^3.1.5" + "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/realtime-js": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.7.3.tgz", - "integrity": "sha512-c7TzL81sx2kqyxsxcDduJcHL9KJdCOoKimGP6lQSqiZKX42ATlBZpWbyy9KFGFBjAP4nyopMf5JhPi2ZH9jyNw==", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.9.3.tgz", + "integrity": "sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ==", "dependencies": { + "@supabase/node-fetch": "^2.6.14", "@types/phoenix": "^1.5.4", - "@types/websocket": "^1.0.3", - "websocket": "^1.0.34" + "@types/ws": "^8.5.10", + "ws": "^8.14.2" + } + }, + "node_modules/@supabase/ssr": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.1.0.tgz", + "integrity": "sha512-bIVrkqjAK5G3KjkIMKYKtAOlCgRRplEWjrlyRyXSOYtgDieiOhk2ZyNAPsEOa1By9OZVxuX5eAW1fitdnuxayw==", + "dependencies": { + "cookie": "^0.5.0", + "ramda": "^0.29.0" + }, + "peerDependencies": { + "@supabase/supabase-js": "^2.33.1" } }, "node_modules/@supabase/storage-js": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.1.tgz", - "integrity": "sha512-nkR0fQA9ScAtIKA3vNoPEqbZv1k5B5HVRYEvRWdlP6mUpFphM9TwPL2jZ/ztNGMTG5xT6SrHr+H7Ykz8qzbhjw==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.5.tgz", + "integrity": "sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==", "dependencies": { - "cross-fetch": "^3.1.5" + "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/supabase-js": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.26.0.tgz", - "integrity": "sha512-RXmTPTobaYAwkSobadHZmEVLmzX3SGrtRZIGfLWnLv92VzBRrjuXn0a+bJqKl50GUzsyqPA+j5pod7EwMkcH5A==", + "version": "2.42.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.42.0.tgz", + "integrity": "sha512-1PDqJiA4iG45w3AAu6xkccJ3wPqlGJUoz9CPhScRLLTStxhewYhz0mjryTpXz1kgtNHdUAsirALreezn8UZMjA==", "dependencies": { - "@supabase/functions-js": "^2.1.0", - "@supabase/gotrue-js": "^2.31.0", - "@supabase/postgrest-js": "^1.7.0", - "@supabase/realtime-js": "^2.7.3", - "@supabase/storage-js": "^2.5.1", - "cross-fetch": "^3.1.5" + "@supabase/auth-js": "2.63.0", + "@supabase/functions-js": "2.2.2", + "@supabase/node-fetch": "2.6.15", + "@supabase/postgrest-js": "1.15.0", + "@supabase/realtime-js": "2.9.3", + "@supabase/storage-js": "2.5.5" } }, "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "dependencies": { "tslib": "^2.4.0" } }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, "node_modules/@types/node": { - "version": "20.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", - "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==" + "version": "20.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", + "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/phoenix": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.0.tgz", - "integrity": "sha512-qwfpsHmFuhAS/dVd4uBIraMxRd56vwBUYQGZ6GpXnFuM2XMRFJbIyruFKKlW2daQliuYZwe0qfn/UjFCDKic5g==" + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.4.tgz", + "integrity": "sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true }, "node_modules/@types/react": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz", - "integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==", + "version": "18.2.48", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", + "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -442,321 +392,106 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", - "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, "dependencies": { "@types/react": "*" } }, "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", + "dev": true }, - "node_modules/@types/websocket": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", - "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dependencies": { "@types/node": "*" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", - "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", - "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", - "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", - "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", - "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.55.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, + "node_modules/autoprefixer": { + "version": "10.4.17", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", + "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "browserslist": "^4.22.2", + "caniuse-lite": "^1.0.30001578", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >=14" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", - "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" + "peerDependencies": { + "postcss": "^8.1.0" } }, "node_modules/balanced-match": { @@ -764,20 +499,29 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -785,16 +529,35 @@ "node": ">=8" } }, - "node_modules/bufferutil": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", - "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", - "hasInstallScript": true, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "node-gyp-build": "^4.3.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">=6.14.2" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/busboy": { @@ -808,31 +571,18 @@ "node": ">=10.16.0" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "engines": { - "node": ">=6" + "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001466", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz", - "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==", + "version": "1.0.30001605", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", + "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", "funding": [ { "type": "opencollective", @@ -841,22 +591,45 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=10" + "node": ">= 8.10.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/client-only": { @@ -880,17 +653,20 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } }, - "node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dependencies": { - "node-fetch": "^2.6.11" + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" } }, "node_modules/cross-spawn": { @@ -906,757 +682,69 @@ "node": ">= 8" } }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, - "node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } + "node_modules/electron-to-chromium": { + "version": "1.4.728", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.728.tgz", + "integrity": "sha512-Ud1v7hJJYIqehlUJGqR6PF1Ek8l80zWwxA6nGxigBsGJ9f9M2fciHyrIiNMerSHSH3p+0/Ia7jIlnDkt41h5cw==" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, + "iconv-lite": "^0.6.2" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { - "node": ">=10.13.0" + "node": ">=6" } }, - "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.3.tgz", - "integrity": "sha512-1lXwdFi29fKxzeugof/TUE7lpHyJQt5+U4LaUHyvQfHjvsWO77vFNicJv5sX6k0VDVSbnfz0lw+avxI+CinbMg==", - "dev": true, - "dependencies": { - "@next/eslint-plugin-next": "13.4.3", - "@rushstack/eslint-patch": "^1.1.3", - "@typescript-eslint/parser": "^5.42.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.31.7", - "eslint-plugin-react-hooks": "^4.5.0" - }, - "peerDependencies": { - "eslint": "^7.23.0 || ^8.0.0", - "typescript": ">=3.3.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", - "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.10.0", - "get-tsconfig": "^4.2.0", - "globby": "^13.1.2", - "is-core-module": "^2.10.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.4" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1672,7 +760,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -1680,40 +767,18 @@ "node": ">= 6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dependencies": { "reusify": "^1.0.4" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1721,138 +786,78 @@ "node": ">=8" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz", - "integrity": "sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "node_modules/geist": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/geist/-/geist-1.3.0.tgz", + "integrity": "sha512-IoGBfcqVEYB4bEwsfHd35jF4+X9LHRPYZymHL4YOltHSs9LJa24DYs1Z7rEMQ/lsEvaAIc61Y9aUxgcJaQ8lrg==", + "peerDependencies": { + "next": ">=13.2.0 <15.0.0-0" } }, "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1869,341 +874,56 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "function-bind": "^1.1.1" + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2212,6 +932,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2223,213 +951,42 @@ "node": ">=0.10.0" } }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, "funding": { - "url": "https://github.com/sponsors/panva" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" } }, "node_modules/js-tokens": { @@ -2437,97 +994,18 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dev": true, - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -2541,22 +1019,17 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "engines": { - "node": ">=10" + "node": "14 || >=16.14" } }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -2565,7 +1038,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -2575,34 +1047,47 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, + "node": ">=16 || 14 >=14.17" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } }, "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.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2610,45 +1095,38 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, "node_modules/next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", - "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.4.tgz", + "integrity": "sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==", "dependencies": { - "@next/env": "13.4.3", - "@swc/helpers": "0.5.1", + "@next/env": "14.1.4", + "@swc/helpers": "0.5.2", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "zod": "3.21.4" + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.8.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.3", - "@next/swc-darwin-x64": "13.4.3", - "@next/swc-linux-arm64-gnu": "13.4.3", - "@next/swc-linux-arm64-musl": "13.4.3", - "@next/swc-linux-x64-gnu": "13.4.3", - "@next/swc-linux-x64-musl": "13.4.3", - "@next/swc-win32-arm64-msvc": "13.4.3", - "@next/swc-win32-ia32-msvc": "13.4.3", - "@next/swc-win32-x64-msvc": "13.4.3" + "@next/swc-darwin-arm64": "14.1.4", + "@next/swc-darwin-x64": "14.1.4", + "@next/swc-linux-arm64-gnu": "14.1.4", + "@next/swc-linux-arm64-musl": "14.1.4", + "@next/swc-linux-x64-gnu": "14.1.4", + "@next/swc-linux-x64-musl": "14.1.4", + "@next/swc-win32-arm64-msvc": "14.1.4", + "@next/swc-win32-ia32-msvc": "14.1.4", + "@next/swc-win32-x64-msvc": "14.1.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -2657,267 +1135,73 @@ "@opentelemetry/api": { "optional": true }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, "sass": { "optional": true } } }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "whatwg-url": "^5.0.0" + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "node": "^10 || ^12 || >=14" } }, - "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, "node_modules/path-key": { @@ -2931,16 +1215,21 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/picocolors": { @@ -2952,7 +1241,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -2960,10 +1248,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, "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.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", @@ -2972,10 +1276,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.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -2983,33 +1291,120 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" } }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, "engines": { - "node": ">=6" + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" } }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3029,6 +1424,15 @@ } ] }, + "node_modules/ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -3052,42 +1456,31 @@ "react": "^18.2.0" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.10.0" } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3098,14 +1491,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3115,20 +1500,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3151,19 +1522,11 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "node_modules/scheduler": { "version": "0.23.0", @@ -3173,26 +1536,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3212,49 +1555,25 @@ "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -3263,71 +1582,50 @@ "node": ">=10.0.0" } }, - "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "dev": true, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -3338,24 +1636,38 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" } }, "node_modules/styled-jsx": { @@ -3380,22 +1692,31 @@ } } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dependencies": { - "has-flag": "^4.0.0" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3403,51 +1724,65 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": ">=14.0.0" } }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -3460,174 +1795,72 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, - "node_modules/unbox-primitive": { + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, - "node_modules/websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", - "dependencies": { - "bufferutil": "^4.0.1", - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "typedarray-to-buffer": "^3.1.5", - "utf-8-validate": "^5.0.2", - "yaeti": "^0.0.6" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/websocket/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/websocket/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -3651,2759 +1884,120 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", - "engines": { - "node": ">=0.10.32" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - }, - "dependencies": { - "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==" - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==" - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" - }, - "@next/env": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", - "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" - }, - "@next/eslint-plugin-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.3.tgz", - "integrity": "sha512-5B0uOnh7wyUY9vNNdIA6NUvWozhrZaTMZOzdirYAefqD0ZBK5C/h3+KMYdCKrR7JrXGvVpWnHtv54b3dCzwICA==", - "dev": true, - "requires": { - "glob": "7.1.7" - } - }, - "@next/swc-darwin-arm64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", - "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", - "optional": true - }, - "@next/swc-darwin-x64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", - "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", - "optional": true - }, - "@next/swc-linux-arm64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", - "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", - "optional": true - }, - "@next/swc-linux-arm64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", - "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", - "optional": true - }, - "@next/swc-linux-x64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", - "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", - "optional": true - }, - "@next/swc-linux-x64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", - "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", - "optional": true - }, - "@next/swc-win32-arm64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", - "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", - "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", - "optional": true - }, - "@next/swc-win32-x64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", - "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", - "optional": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - } - }, - "@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "@supabase/auth-helpers-nextjs": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.7.2.tgz", - "integrity": "sha512-n5IyGBYJV/WiR5Rgw4CUaiJYiOv9yW2of4ZP4EyzKt2O6/6rztt7PcGE4AoK2vERw+fb5F2QtJBdt6J5eOYCCw==", - "requires": { - "@supabase/auth-helpers-shared": "0.4.1", - "set-cookie-parser": "^2.6.0" - } - }, - "@supabase/auth-helpers-shared": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.4.1.tgz", - "integrity": "sha512-IEDX9JzWkIjQiLUaP4Qy5YDiG0jFQatWfS+jw8cCQs6QfbNdEPd2Y3qonwGHnM90CZom9SvjuylBv2pFVAL7Lw==", - "requires": { - "jose": "^4.14.3" - } - }, - "@supabase/functions-js": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.1.2.tgz", - "integrity": "sha512-QCR6pwJs9exCl37bmpMisUd6mf+0SUBJ6mUpiAjEkSJ/+xW8TCuO14bvkWHADd5hElJK9MxNlMQXxSA4DRz9nQ==", - "requires": { - "cross-fetch": "^3.1.5" - } - }, - "@supabase/gotrue-js": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.31.0.tgz", - "integrity": "sha512-YcwlbbNfedlue/HVIXtYBb4fuOrs29gNOTl6AmyxPp4zryRxzFvslVN9kmLDBRUAVU9fnPJh2bgOR3chRjJX5w==", - "requires": { - "cross-fetch": "^3.1.5" - } - }, - "@supabase/postgrest-js": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.7.1.tgz", - "integrity": "sha512-xPRYLaZrkLbXNlzmHW6Wtf9hmcBLjjI5xUz2zj8oE2hgXGaYoZBBkpN9bmW9i17Z1f6Ujxa942AqK439XOA36A==", - "requires": { - "cross-fetch": "^3.1.5" - } - }, - "@supabase/realtime-js": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.7.3.tgz", - "integrity": "sha512-c7TzL81sx2kqyxsxcDduJcHL9KJdCOoKimGP6lQSqiZKX42ATlBZpWbyy9KFGFBjAP4nyopMf5JhPi2ZH9jyNw==", - "requires": { - "@types/phoenix": "^1.5.4", - "@types/websocket": "^1.0.3", - "websocket": "^1.0.34" - } - }, - "@supabase/storage-js": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.1.tgz", - "integrity": "sha512-nkR0fQA9ScAtIKA3vNoPEqbZv1k5B5HVRYEvRWdlP6mUpFphM9TwPL2jZ/ztNGMTG5xT6SrHr+H7Ykz8qzbhjw==", - "requires": { - "cross-fetch": "^3.1.5" - } - }, - "@supabase/supabase-js": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.26.0.tgz", - "integrity": "sha512-RXmTPTobaYAwkSobadHZmEVLmzX3SGrtRZIGfLWnLv92VzBRrjuXn0a+bJqKl50GUzsyqPA+j5pod7EwMkcH5A==", - "requires": { - "@supabase/functions-js": "^2.1.0", - "@supabase/gotrue-js": "^2.31.0", - "@supabase/postgrest-js": "^1.7.0", - "@supabase/realtime-js": "^2.7.3", - "@supabase/storage-js": "^2.5.1", - "cross-fetch": "^3.1.5" - } - }, - "@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "requires": { - "tslib": "^2.4.0" - } - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/node": { - "version": "20.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", - "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==" - }, - "@types/phoenix": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.0.tgz", - "integrity": "sha512-qwfpsHmFuhAS/dVd4uBIraMxRd56vwBUYQGZ6GpXnFuM2XMRFJbIyruFKKlW2daQliuYZwe0qfn/UjFCDKic5g==" - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/react": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz", - "integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", - "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@types/websocket": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", - "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", - "requires": { - "@types/node": "*" - } - }, - "@typescript-eslint/parser": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", - "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", - "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0" - } - }, - "@typescript-eslint/types": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", - "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", - "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", - "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.55.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } }, - "ansi-styles": { + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { + "dependencies": { "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "requires": { - "deep-equal": "^2.0.5" - } - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "axe-core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", - "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", - "dev": true - }, - "axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "requires": { - "deep-equal": "^2.0.5" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "bufferutil": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", - "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "caniuse-lite": { - "version": "1.0.30001466", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz", - "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "requires": { - "node-fetch": "^2.6.11" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "eslint-config-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.3.tgz", - "integrity": "sha512-1lXwdFi29fKxzeugof/TUE7lpHyJQt5+U4LaUHyvQfHjvsWO77vFNicJv5sX6k0VDVSbnfz0lw+avxI+CinbMg==", - "dev": true, - "requires": { - "@next/eslint-plugin-next": "13.4.3", - "@rushstack/eslint-patch": "^1.1.3", - "@typescript-eslint/parser": "^5.42.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.31.7", - "eslint-plugin-react-hooks": "^4.5.0" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-import-resolver-typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", - "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.10.0", - "get-tsconfig": "^4.2.0", - "globby": "^13.1.2", - "is-core-module": "^2.10.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.4" + "engines": { + "node": ">=8" }, - "dependencies": { - "globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", - "dev": true, - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "requires": { - "debug": "^3.2.7" + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "engines": { + "node": ">=8" } }, - "eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dev": true, - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dev": true, - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "requires": {} - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "requires": { - "type": "^2.7.2" - }, - "dependencies": { - "type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-tsconfig": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz", - "integrity": "sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==", - "dev": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dev": true, - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", - "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", - "requires": { - "@next/env": "13.4.3", - "@next/swc-darwin-arm64": "13.4.3", - "@next/swc-darwin-x64": "13.4.3", - "@next/swc-linux-arm64-gnu": "13.4.3", - "@next/swc-linux-arm64-musl": "13.4.3", - "@next/swc-linux-x64-gnu": "13.4.3", - "@next/swc-linux-x64-musl": "13.4.3", - "@next/swc-win32-arm64-msvc": "13.4.3", - "@next/swc-win32-ia32-msvc": "13.4.3", - "@next/swc-win32-x64-msvc": "13.4.3", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "zod": "3.21.4" - } - }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "dev": true, - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "requires": { - "internal-slot": "^1.0.4" - } - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "strip-ansi": { + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { + "dependencies": { "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "requires": { - "client-only": "0.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, - "requires": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "requires": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==" - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", - "requires": { + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { "bufferutil": "^4.0.1", - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "typedarray-to-buffer": "^3.1.5", - "utf-8-validate": "^5.0.2", - "yaeti": "^0.0.6" + "utf-8-validate": ">=5.0.2" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } + "peerDependenciesMeta": { + "bufferutil": { + "optional": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "utf-8-validate": { + "optional": true } } }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - }, - "zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" } } } diff --git a/examples/auth/nextjs/package.json b/examples/auth/nextjs/package.json index 1e70631c6a7..a9997ef9250 100644 --- a/examples/auth/nextjs/package.json +++ b/examples/auth/nextjs/package.json @@ -1,26 +1,26 @@ { - "name": "full-nextjs-auth-helpers", - "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", - "start": "next start", - "lint": "next lint" + "start": "next start" }, "dependencies": { - "@supabase/auth-helpers-nextjs": "^0.7.1", - "@supabase/supabase-js": "^2.26.0", - "@types/node": "^20.2.3", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", - "eslint": "^8.41.0", - "next": "^13.4.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "typescript": "^5.0.4" + "@supabase/ssr": "latest", + "@supabase/supabase-js": "latest", + "autoprefixer": "10.4.17", + "geist": "^1.2.1", + "next": "latest", + "postcss": "8.4.33", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwindcss": "3.4.1", + "typescript": "5.3.3" }, "devDependencies": { - "eslint-config-next": "^13.4.3" + "@types/node": "20.11.5", + "@types/react": "18.2.48", + "@types/react-dom": "18.2.18", + "encoding": "^0.1.13" } } diff --git a/examples/auth/nextjs/postcss.config.js b/examples/auth/nextjs/postcss.config.js new file mode 100644 index 00000000000..12a703d900d --- /dev/null +++ b/examples/auth/nextjs/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/examples/auth/nextjs/public/next.svg b/examples/auth/nextjs/public/next.svg deleted file mode 100644 index 5174b28c565..00000000000 --- a/examples/auth/nextjs/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/auth/nextjs/public/thirteen.svg b/examples/auth/nextjs/public/thirteen.svg deleted file mode 100644 index 8977c1bd123..00000000000 --- a/examples/auth/nextjs/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/auth/nextjs/public/vercel.svg b/examples/auth/nextjs/public/vercel.svg deleted file mode 100644 index d2f84222734..00000000000 --- a/examples/auth/nextjs/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/auth/nextjs/supabase/.gitignore b/examples/auth/nextjs/supabase/.gitignore new file mode 100644 index 00000000000..a3ad88055b7 --- /dev/null +++ b/examples/auth/nextjs/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/examples/auth/nextjs/supabase/config.toml b/examples/auth/nextjs/supabase/config.toml new file mode 100644 index 00000000000..3ef6eb65324 --- /dev/null +++ b/examples/auth/nextjs/supabase/config.toml @@ -0,0 +1,161 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "nextjs" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +[auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" + +[analytics] +enabled = false +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/examples/auth/nextjs/supabase/seed.sql b/examples/auth/nextjs/supabase/seed.sql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/auth/nextjs/tailwind.config.js b/examples/auth/nextjs/tailwind.config.js new file mode 100644 index 00000000000..8c3a2ab7866 --- /dev/null +++ b/examples/auth/nextjs/tailwind.config.js @@ -0,0 +1,20 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./app/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + colors: { + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + btn: { + background: "hsl(var(--btn-background))", + "background-hover": "hsl(var(--btn-background-hover))", + }, + }, + }, + }, + plugins: [], +}; diff --git a/examples/auth/nextjs/utils/supabase/client.ts b/examples/auth/nextjs/utils/supabase/client.ts new file mode 100644 index 00000000000..e2660d0f654 --- /dev/null +++ b/examples/auth/nextjs/utils/supabase/client.ts @@ -0,0 +1,7 @@ +import { createBrowserClient } from "@supabase/ssr"; + +export const createClient = () => + createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + ); diff --git a/examples/auth/nextjs/utils/supabase/middleware.ts b/examples/auth/nextjs/utils/supabase/middleware.ts new file mode 100644 index 00000000000..8c6338c8026 --- /dev/null +++ b/examples/auth/nextjs/utils/supabase/middleware.ts @@ -0,0 +1,78 @@ +import { createServerClient, type CookieOptions } from "@supabase/ssr"; +import { type NextRequest, NextResponse } from "next/server"; + +export const updateSession = async (request: NextRequest) => { + // This `try/catch` block is only here for the interactive tutorial. + // Feel free to remove once you have Supabase connected. + try { + // Create an unmodified response + let response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return request.cookies.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + // If the cookie is updated, update the cookies for the request and response + request.cookies.set({ + name, + value, + ...options, + }); + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + response.cookies.set({ + name, + value, + ...options, + }); + }, + remove(name: string, options: CookieOptions) { + // If the cookie is removed, update the cookies for the request and response + request.cookies.set({ + name, + value: "", + ...options, + }); + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + response.cookies.set({ + name, + value: "", + ...options, + }); + }, + }, + }, + ); + + // This will refresh session if expired - required for Server Components + // https://supabase.com/docs/guides/auth/server-side/nextjs + await supabase.auth.getUser(); + + return response; + } catch (e) { + // If you are here, a Supabase client could not be created! + // This is likely because you have not set up environment variables. + // Check out http://localhost:3000 for Next Steps. + return NextResponse.next({ + request: { + headers: request.headers, + }, + }); + } +}; diff --git a/examples/auth/nextjs/utils/supabase/server.ts b/examples/auth/nextjs/utils/supabase/server.ts new file mode 100644 index 00000000000..ecadfb1c02b --- /dev/null +++ b/examples/auth/nextjs/utils/supabase/server.ts @@ -0,0 +1,36 @@ +import { createServerClient, type CookieOptions } from "@supabase/ssr"; +import { cookies } from "next/headers"; + +export const createClient = () => { + const cookieStore = cookies(); + + return createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + try { + cookieStore.set({ name, value, ...options }); + } catch (error) { + // The `set` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + remove(name: string, options: CookieOptions) { + try { + cookieStore.set({ name, value: "", ...options }); + } catch (error) { + // The `delete` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + }, + }, + ); +}; diff --git a/examples/slack-clone/nextjs-slack-clone/.env.local.example b/examples/slack-clone/nextjs-slack-clone/.env.example similarity index 77% rename from examples/slack-clone/nextjs-slack-clone/.env.local.example rename to examples/slack-clone/nextjs-slack-clone/.env.example index 297256db311..e3a1289f58d 100644 --- a/examples/slack-clone/nextjs-slack-clone/.env.local.example +++ b/examples/slack-clone/nextjs-slack-clone/.env.example @@ -1,4 +1,4 @@ # Get these from your API settings: https://supabase.com/dashboard/project/_/settings/api NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co -NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key \ No newline at end of file +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/examples/slack-clone/nextjs-slack-clone/README.md b/examples/slack-clone/nextjs-slack-clone/README.md index 183701a7358..a29ae341eb3 100644 --- a/examples/slack-clone/nextjs-slack-clone/README.md +++ b/examples/slack-clone/nextjs-slack-clone/README.md @@ -61,10 +61,10 @@ Simply clone this repo locally and proceed to the next section. ### Required configuration -Copy the `.env.local.example` file into a file named `.env.local` in the root directory of the example: +Copy the `.env.example` file into a file named `.env.local` in the root directory of the example: ```bash -cp .env.local.example .env.local +cp .env.example .env.local ``` Set your Supabase details from [step 3](#3-get-the-url-and-key) above: diff --git a/examples/user-management/expo-user-management/.env.example b/examples/user-management/expo-user-management/.env.example new file mode 100644 index 00000000000..dd6bd19b418 --- /dev/null +++ b/examples/user-management/expo-user-management/.env.example @@ -0,0 +1,4 @@ +# Get these from your API settings: https://supabase.com/dashboard/project/_/settings/api + +EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +EXPO_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/examples/user-management/expo-user-management/README.md b/examples/user-management/expo-user-management/README.md index 69dd32c9fa4..48b379c0b59 100644 --- a/examples/user-management/expo-user-management/README.md +++ b/examples/user-management/expo-user-management/README.md @@ -24,7 +24,7 @@ The `anon` key is your client-side API key. It allows "anonymous access" to your **_NOTE_**: The `service_role` key has full access to your data, bypassing any security policies. These keys have to be kept secret and are meant to be used in server environments and never on a client or browser. -Set the details in the `/lib/supabase.js` file. +Run `cp .env.example .env` and fill your URL and anon key in the newly created `.env` file. ### 4. Install the dependencies & run the project: @@ -39,7 +39,7 @@ npm install In order to get the file picker to work you must first prebuild the project before running it. ```bash -expo prebuild +npm run prebuild ``` ### 5. Run the application diff --git a/examples/user-management/expo-user-management/package-lock.json b/examples/user-management/expo-user-management/package-lock.json index 7ef9fb966e1..825acdbf8c6 100644 --- a/examples/user-management/expo-user-management/package-lock.json +++ b/examples/user-management/expo-user-management/package-lock.json @@ -11,15 +11,16 @@ "@expo/webpack-config": "^18.0.3", "@react-native-async-storage/async-storage": "^1.17.9", "@supabase/supabase-js": "^2.0.4", - "expo": "~46.0.9", + "expo": "~46.0.21", "expo-splash-screen": "~0.16.2", "expo-status-bar": "~1.4.0", "react": "18.0.0", "react-dom": "18.0.0", - "react-native": "0.69.5", + "react-native": "0.69.9", "react-native-document-picker": "^8.1.1", "react-native-elements": "^3.4.2", - "react-native-url-polyfill": "^1.3.0" + "react-native-url-polyfill": "^1.3.0", + "react-native-web": "~0.18.7" }, "devDependencies": { "@babel/core": "^7.12.9", @@ -1849,18 +1850,18 @@ } }, "node_modules/@expo/cli": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.2.11.tgz", - "integrity": "sha512-TIlylp3nghiEdlVliZRcBg8Yb++tnU92HinuQQZznVGFXFCoqJ210SPUJS1j3rxxltt8NhIJjL9OTO7PYRqnsQ==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.3.3.tgz", + "integrity": "sha512-5uDbjLntXkJOPx2SOZ6Pj9MC448YWtGenBJE+jNBfAbUPaf62Fy9uIyWWeKeRWXNfSs9jmOVpIgyYLTklV1vpg==", "dependencies": { "@babel/runtime": "^7.14.0", "@expo/code-signing-certificates": "^0.0.2", "@expo/config": "~7.0.1", "@expo/config-plugins": "~5.0.1", - "@expo/dev-server": "~0.1.119", + "@expo/dev-server": "0.1.120", "@expo/devcert": "^1.0.0", "@expo/json-file": "^8.2.35", - "@expo/metro-config": "~0.3.18", + "@expo/metro-config": "~0.4.0", "@expo/osascript": "^2.0.31", "@expo/package-manager": "~0.0.53", "@expo/plist": "^0.0.18", @@ -1971,17 +1972,6 @@ "node": ">=8" } }, - "node_modules/@expo/cli/node_modules/minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@expo/cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2259,20 +2249,17 @@ } }, "node_modules/@expo/dev-server": { - "version": "0.1.124", - "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.1.124.tgz", - "integrity": "sha512-iHczVcf+rgWupCY/3b3ePIizNtzsy1O/w8jdKv3bKvoOfXiVIVOo4KGiVDpAJOahKiMOsRlbKeemB8OLNKzdSA==", + "version": "0.1.120", + "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.1.120.tgz", + "integrity": "sha512-x5/jCv0EOpz6FyehXpI5bgDQTVsGZYvgISkAw7n60RhtG+aid6N2CCR9SDMCH70XaUpFnfTW9qvderpCEj7Puw==", "dependencies": { "@expo/bunyan": "4.0.0", - "@expo/metro-config": "~0.5.1", + "@expo/metro-config": "~0.4.0", "@expo/osascript": "2.0.33", - "@expo/spawn-async": "^1.5.0", - "body-parser": "^1.20.1", + "body-parser": "1.19.0", "chalk": "^4.0.0", "connect": "^3.7.0", "fs-extra": "9.0.0", - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1", "node-fetch": "^2.6.0", "open": "^8.3.0", "resolve-from": "^5.0.0", @@ -2281,50 +2268,16 @@ "temp-dir": "^2.0.0" } }, - "node_modules/@expo/dev-server/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "node_modules/@expo/dev-server/node_modules/@expo/osascript": { + "version": "2.0.33", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.0.33.tgz", + "integrity": "sha512-FQinlwHrTlJbntp8a7NAlCKedVXe06Va/0DSLXRO8lZVtgbEMrYYSUZWQNcOlNtc58c2elNph6z9dMOYwSo3JQ==", "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@expo/dev-server/node_modules/@expo/config": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-7.0.3.tgz", - "integrity": "sha512-joVtB5o+NF40Tmsdp65UzryRtbnCuMbXkVO4wJnNJO4aaK0EYLdHCYSewORVqNcDfGN0LphQr8VTG2npbd9CJA==", - "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~5.0.3", - "@expo/config-types": "^47.0.0", - "@expo/json-file": "8.2.36", - "getenv": "^1.0.0", - "glob": "7.1.6", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", - "semver": "7.3.2", - "slugify": "^1.3.4", - "sucrase": "^3.20.0" - } - }, - "node_modules/@expo/dev-server/node_modules/@expo/config-types": { - "version": "47.0.0", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-47.0.0.tgz", - "integrity": "sha512-r0pWfuhkv7KIcXMUiNACJmJKKwlTBGMw9VZHNdppS8/0Nve8HZMTkNRFQzTHW1uH3pBj8jEXpyw/2vSWDHex9g==" - }, - "node_modules/@expo/dev-server/node_modules/@expo/metro-config": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.5.2.tgz", - "integrity": "sha512-W1qsZPA5BXuRBkNLydKBYQ1+ubObhOK0gk2Fpc+XnhW+UUIHC9sDR5pZRYGNSnDDc3rG8y7c32UzSW9nlK+mog==", - "dependencies": { - "@expo/config": "~7.0.2", - "@expo/json-file": "8.2.36", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "find-yarn-workspace-root": "~2.0.0", - "getenv": "^1.0.0", - "resolve-from": "^5.0.0", - "sucrase": "^3.20.0" + "@expo/spawn-async": "^1.5.0", + "exec-async": "^2.2.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/@expo/dev-server/node_modules/ansi-styles": { @@ -2386,25 +2339,6 @@ "node": ">=10" } }, - "node_modules/@expo/dev-server/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@expo/dev-server/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2425,9 +2359,9 @@ } }, "node_modules/@expo/dev-server/node_modules/jsonfile/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { "node": ">= 10.0.0" } @@ -2463,9 +2397,9 @@ } }, "node_modules/@expo/devcert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.0.0.tgz", - "integrity": "sha512-cahGyQCmpZmHpn2U04NR9KwsOIZy7Rhsw8Fg4q+A6563lIJxbkrgPnxq/O3NQAh3ohEvOXOOnoFx0b4yycCkpQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.1.0.tgz", + "integrity": "sha512-ghUVhNJQOCTdQckSGTHctNp/0jzvVoMMkVh+6SHn+TZj8sU15U/npXIDt8NtQp0HedlPaCgkVdMu8Sacne0aEA==", "dependencies": { "application-config-path": "^0.1.0", "command-exists": "^1.2.4", @@ -2479,7 +2413,7 @@ "rimraf": "^2.6.2", "sudo-prompt": "^8.2.0", "tmp": "^0.0.33", - "tslib": "^1.10.0" + "tslib": "^2.4.0" } }, "node_modules/@expo/devcert/node_modules/debug": { @@ -2713,9 +2647,9 @@ } }, "node_modules/@expo/metro-config": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.3.22.tgz", - "integrity": "sha512-R81sLbaeUBjN8IXcxiVx7GcpSj8z7szILl1b5yJDb38WdIFwxhrseA5wXaTT1yMhI+59w6n99T2qtFV2yD5qYA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.4.0.tgz", + "integrity": "sha512-QhOiotuzklalLbbsTMXJ5v4q4jffQ5xXhy1zsosgc2DL/ZzUr/Yhm3xUcOGnPQ2x7UyeY9Tl3njPHBOJJe7CSA==", "dependencies": { "@expo/config": "7.0.1", "@expo/json-file": "8.2.36", @@ -2792,9 +2726,9 @@ } }, "node_modules/@expo/osascript": { - "version": "2.0.33", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.0.33.tgz", - "integrity": "sha512-FQinlwHrTlJbntp8a7NAlCKedVXe06Va/0DSLXRO8lZVtgbEMrYYSUZWQNcOlNtc58c2elNph6z9dMOYwSo3JQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.1.0.tgz", + "integrity": "sha512-bOhuFnlRaS7CU33+rFFIWdcET/Vkyn1vsN8BYFwCDEF5P1fVVvYN7bFOsQLTMD3nvi35C1AGmtqUr/Wfv8Xaow==", "dependencies": { "@expo/spawn-async": "^1.5.0", "exec-async": "^2.2.0" @@ -2804,11 +2738,11 @@ } }, "node_modules/@expo/package-manager": { - "version": "0.0.56", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-0.0.56.tgz", - "integrity": "sha512-PGk34uz4XDyhoNIlPh2D+BDsiXYuW2jXavTiax8d32uvHlRO6FN0cAsqlWD6fx3H2hRn8cU/leTuc4M7pYovCQ==", + "version": "0.0.60", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-0.0.60.tgz", + "integrity": "sha512-MdV7dpFA4aI8HIW0xsW2DBUem5aFKL8+/v5LXKPZuXmYW02/EXPSp7DBJAwow8ULpa3Q2VlYfb46hWPre3hw4A==", "dependencies": { - "@expo/json-file": "8.2.36", + "@expo/json-file": "^8.2.37", "@expo/spawn-async": "^1.5.0", "ansi-regex": "^5.0.0", "chalk": "^4.0.0", @@ -2820,6 +2754,24 @@ "sudo-prompt": "9.1.1" } }, + "node_modules/@expo/package-manager/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@expo/package-manager/node_modules/@expo/json-file": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz", + "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==", + "dependencies": { + "@babel/code-frame": "~7.10.4", + "json5": "^2.2.2", + "write-file-atomic": "^2.3.0" + } + }, "node_modules/@expo/package-manager/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3225,9 +3177,9 @@ } }, "node_modules/@expo/xcpretty": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.2.2.tgz", - "integrity": "sha512-Lke/geldJqUV0Dfxg5/QIOugOzdqZ/rQ9yHKSgGbjZtG1uiSqWyFwWvXmrdd3/sIdX33eykGvIcf+OrvvcXVUw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.3.1.tgz", + "integrity": "sha512-sqXgo1SCv+j4VtYEwl/bukuOIBrVgx6euIoCat3Iyx5oeoXwEA2USCoeL0IPubflMxncA2INkqJ/Wr3NGrSgzw==", "dependencies": { "@babel/code-frame": "7.10.4", "chalk": "^4.1.0", @@ -3332,11 +3284,11 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "node_modules/@graphql-typed-document-node/core": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@hapi/hoek": { @@ -3640,9 +3592,9 @@ } }, "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3657,6 +3609,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -5442,11 +5395,17 @@ "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" }, "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ansi-fragments": { @@ -5512,9 +5471,9 @@ "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==" }, "node_modules/application-config-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/application-config-path/-/application-config-path-0.1.0.tgz", - "integrity": "sha512-lljTpVvFteShrHuKRvweZfa9o/Nc34Y8r5/1Lqh/yyKaspRT2J3fkEiSSk1YLG8ZSVyU7yHysRy9zcDDS2aH1Q==" + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/application-config-path/-/application-config-path-0.1.1.tgz", + "integrity": "sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==" }, "node_modules/arg": { "version": "4.1.0", @@ -5606,11 +5565,6 @@ "node": ">=4" } }, - "node_modules/ast-types/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, "node_modules/astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -6039,26 +5993,31 @@ "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==" }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", + "bytes": "3.1.0", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", + "depd": "~1.1.2", + "http-errors": "1.7.2", "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/debug": { @@ -6069,28 +6028,50 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/body-parser/node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, + "node_modules/body-parser/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/body-parser/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "engines": { - "node": ">= 0.8" + "node": ">=0.6" + } + }, + "node_modules/body-parser/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/body-parser/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" } }, "node_modules/bonjour-service": { @@ -6341,11 +6322,6 @@ "tslib": "^2.0.3" } }, - "node_modules/camel-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -6775,9 +6751,12 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/component-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", - "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.2.tgz", + "integrity": "sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/compressible": { "version": "2.0.18", @@ -7099,6 +7078,15 @@ "node": ">=4" } }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "node_modules/cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -7157,6 +7145,14 @@ "postcss": "^8.0.9" } }, + "node_modules/css-in-js-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", + "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "dependencies": { + "hyphenate-style-name": "^1.0.3" + } + }, "node_modules/css-loader": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", @@ -7750,11 +7746,6 @@ "tslib": "^2.0.3" } }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8161,23 +8152,23 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/expo": { - "version": "46.0.9", - "resolved": "https://registry.npmjs.org/expo/-/expo-46.0.9.tgz", - "integrity": "sha512-UsBjm0BL7w+OyF6kypVPrk3jhg9cCXF0D9CaOWQ+cedm7oT4mTVQx9+A45VsDvLzNWBjJejZQZ1PFKqOY5HNcQ==", + "version": "46.0.21", + "resolved": "https://registry.npmjs.org/expo/-/expo-46.0.21.tgz", + "integrity": "sha512-leTI/GZXDN78xIThqimdK3Bk6uQ5dVkuWr+C0U/K0Ng5qDojQhJGtkM2lSS595KVTa3uYP6m0149MBg6Fp3fpA==", "dependencies": { "@babel/runtime": "^7.14.0", - "@expo/cli": "0.2.11", + "@expo/cli": "0.3.3", "@expo/vector-icons": "^13.0.0", "babel-preset-expo": "~9.2.0", "cross-spawn": "^6.0.5", "expo-application": "~4.2.2", - "expo-asset": "~8.6.1", + "expo-asset": "~8.6.3", "expo-constants": "~13.2.4", "expo-file-system": "~14.1.0", - "expo-font": "~10.2.0", + "expo-font": "~10.2.1", "expo-keep-awake": "~10.2.0", "expo-modules-autolinking": "0.10.3", - "expo-modules-core": "0.11.4", + "expo-modules-core": "0.11.10", "fbemitter": "^3.0.0", "getenv": "^1.0.0", "invariant": "^2.2.4", @@ -8202,9 +8193,9 @@ } }, "node_modules/expo-asset": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.6.1.tgz", - "integrity": "sha512-urbUp1YtwH2J0Qc3inGQJdqTjWKML77SeMNgff+iR9MUE8gDkFqSCDjrBi7i5Oj5DDtq43mmtDg8G8ei6Vchcg==", + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.6.3.tgz", + "integrity": "sha512-AOuB0FBbwYUfuLKtQtIsKUvm08d9OAPWZu9NZjUyIvAxmmdVKPUdN5tFUZQXXLRy3SYmk2z76JVQCoaHgJ5wvw==", "dependencies": { "blueimp-md5": "^2.10.0", "expo-constants": "~13.2.2", @@ -8249,9 +8240,9 @@ } }, "node_modules/expo-font": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-10.2.0.tgz", - "integrity": "sha512-2V4EcpmhNoppaLn+lPprZVS+3bmV9hxLPKttKh2u8ghjH/oX9bv3u4JVo77SYh0EfrWO4toqVyXn8pXH8GpbIg==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-10.2.1.tgz", + "integrity": "sha512-sxy5GrdtY+Ka8Wo5wnrcFFeO6MbYC6Dris5wMLqshvVK6BneJNMUsFvwRfvVgg0TzsmMAc3Rlca2xyZ8ettinw==", "dependencies": { "fontfaceobserver": "^2.1.0" }, @@ -8380,9 +8371,9 @@ } }, "node_modules/expo-modules-core": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-0.11.4.tgz", - "integrity": "sha512-8dEYICk7hUi1GPz5hWm8dBuZDGc+4Tm7zDhSIhKApo5jY/5vB4Bk+fjPo693iWn6pp3+XBHT8Ri8rJ3G7wH1vQ==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-0.11.10.tgz", + "integrity": "sha512-wn7bdL1AXMNuuDEFhuIeE65A+dlvBL+6nC5fGy4NO7x3TXPBR1xCgL28i8d8WWyK5evI4z4TVvJp3YYzdapbqQ==", "dependencies": { "compare-versions": "^3.4.0", "invariant": "^2.2.4" @@ -8866,6 +8857,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/fast-loops": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz", + "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==" + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -9323,11 +9319,6 @@ "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/graphql-tag/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -9681,6 +9672,11 @@ "node": ">=10.17.0" } }, + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -9790,6 +9786,15 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "node_modules/inline-style-prefixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz", + "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==", + "dependencies": { + "css-in-js-utils": "^3.1.0", + "fast-loops": "^1.1.3" + } + }, "node_modules/internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -11030,11 +11035,6 @@ "tslib": "^2.0.3" } }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11844,9 +11844,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "dependencies": { "yallist": "^4.0.0" }, @@ -12075,11 +12075,6 @@ "tslib": "^2.0.3" } }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/nocache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", @@ -12167,6 +12162,11 @@ "url": "https://github.com/sponsors/antelle" } }, + "node_modules/normalize-css-color": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/normalize-css-color/-/normalize-css-color-1.0.2.tgz", + "integrity": "sha512-jPJ/V7Cp1UytdidsPqviKEElFQJs22hUUgK5BOPHTwOonNCk7/2qOxhhqzEajmFrWJowADFfOFh1V+aWkRfy+w==" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -12565,11 +12565,6 @@ "tslib": "^2.0.3" } }, - "node_modules/param-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -12610,11 +12605,6 @@ "tslib": "^2.0.3" } }, - "node_modules/pascal-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -12624,12 +12614,66 @@ } }, "node_modules/password-prompt": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", - "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", + "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==", "dependencies": { - "ansi-escapes": "^3.1.0", - "cross-spawn": "^6.0.5" + "ansi-escapes": "^4.3.2", + "cross-spawn": "^7.0.3" + } + }, + "node_modules/password-prompt/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/password-prompt/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/password-prompt/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/password-prompt/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/password-prompt/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/path-browserify": { @@ -13588,12 +13632,12 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", + "bytes": "3.1.0", + "http-errors": "1.7.2", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -13601,6 +13645,47 @@ "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/raw-body/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/raw-body/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -13673,9 +13758,10 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-native": { - "version": "0.69.5", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.69.5.tgz", - "integrity": "sha512-4Psrj1nDMLQjBXVH8n3UikzOHQc8+sa6NbxZQR0XKtpx8uC3HiJBgX+/FIum/RWxfi5J/Dt/+A2gLGmq2Hps8g==", + "version": "0.69.9", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.69.9.tgz", + "integrity": "sha512-I1xqIn47RWxBToO4E6yqyIPSaK9mZnMiscMfrFpWjQr3Gdkicr9y+twmtrRszxaLdQLjHzh/M3y4qOqc3hZnpg==", + "deprecated": "Issues and pull requests filed against this version are not supported. See the React Native release support policy to learn more: https://github.com/reactwg/react-native-releases#releases-support-policy", "dependencies": { "@jest/create-cache-key-function": "^27.0.1", "@react-native-community/cli": "^8.0.4", @@ -13698,7 +13784,7 @@ "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", - "promise": "^8.0.3", + "promise": "^8.2.0", "react-devtools-core": "4.24.0", "react-native-codegen": "^0.69.2", "react-native-gradle-plugin": "^0.0.7", @@ -13897,10 +13983,28 @@ "node": ">=10" } }, + "node_modules/react-native-web": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.12.tgz", + "integrity": "sha512-fboP7yqobJ8InSr4fP+bQ3scOtSQtUoPcR+HWasH8b/fk/RO+mWcJs/8n+lewy9WTZc2D68ha7VwRDviUshEWA==", + "dependencies": { + "@babel/runtime": "^7.18.6", + "create-react-class": "^15.7.0", + "fbjs": "^3.0.4", + "inline-style-prefixer": "^6.0.1", + "normalize-css-color": "^1.0.2", + "postcss-value-parser": "^4.2.0", + "styleq": "^0.1.2" + }, + "peerDependencies": { + "react": "^17.0.2 || ^18.0.0", + "react-dom": "^17.0.2 || ^18.0.0" + } + }, "node_modules/react-native/node_modules/promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", "dependencies": { "asap": "~2.0.6" } @@ -13969,11 +14073,6 @@ "node": ">= 4" } }, - "node_modules/recast/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14453,6 +14552,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/serialize-javascript": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", @@ -15310,6 +15420,11 @@ "postcss": "^8.2.15" } }, + "node_modules/styleq": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz", + "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==" + }, "node_modules/sucrase": { "version": "3.25.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz", @@ -15374,9 +15489,9 @@ } }, "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -15444,19 +15559,27 @@ } }, "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" } }, "node_modules/tar/node_modules/mkdirp": { @@ -15582,31 +15705,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terminal-link/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/terser": { "version": "5.16.9", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.9.tgz", @@ -15812,9 +15910,15 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==" + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/ts-interface-checker": { "version": "0.1.13", @@ -15822,9 +15926,9 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/type": { "version": "1.2.0", @@ -15832,9 +15936,9 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, "node_modules/type-fest": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", - "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "engines": { "node": ">=10" }, @@ -18326,18 +18430,18 @@ } }, "@expo/cli": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.2.11.tgz", - "integrity": "sha512-TIlylp3nghiEdlVliZRcBg8Yb++tnU92HinuQQZznVGFXFCoqJ210SPUJS1j3rxxltt8NhIJjL9OTO7PYRqnsQ==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.3.3.tgz", + "integrity": "sha512-5uDbjLntXkJOPx2SOZ6Pj9MC448YWtGenBJE+jNBfAbUPaf62Fy9uIyWWeKeRWXNfSs9jmOVpIgyYLTklV1vpg==", "requires": { "@babel/runtime": "^7.14.0", "@expo/code-signing-certificates": "^0.0.2", "@expo/config": "~7.0.1", "@expo/config-plugins": "~5.0.1", - "@expo/dev-server": "~0.1.119", + "@expo/dev-server": "0.1.120", "@expo/devcert": "^1.0.0", "@expo/json-file": "^8.2.35", - "@expo/metro-config": "~0.3.18", + "@expo/metro-config": "~0.4.0", "@expo/osascript": "^2.0.31", "@expo/package-manager": "~0.0.53", "@expo/plist": "^0.0.18", @@ -18427,14 +18531,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "requires": { - "yallist": "^4.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18651,20 +18747,17 @@ } }, "@expo/dev-server": { - "version": "0.1.124", - "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.1.124.tgz", - "integrity": "sha512-iHczVcf+rgWupCY/3b3ePIizNtzsy1O/w8jdKv3bKvoOfXiVIVOo4KGiVDpAJOahKiMOsRlbKeemB8OLNKzdSA==", + "version": "0.1.120", + "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.1.120.tgz", + "integrity": "sha512-x5/jCv0EOpz6FyehXpI5bgDQTVsGZYvgISkAw7n60RhtG+aid6N2CCR9SDMCH70XaUpFnfTW9qvderpCEj7Puw==", "requires": { "@expo/bunyan": "4.0.0", - "@expo/metro-config": "~0.5.1", + "@expo/metro-config": "~0.4.0", "@expo/osascript": "2.0.33", - "@expo/spawn-async": "^1.5.0", - "body-parser": "^1.20.1", + "body-parser": "1.19.0", "chalk": "^4.0.0", "connect": "^3.7.0", "fs-extra": "9.0.0", - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1", "node-fetch": "^2.6.0", "open": "^8.3.0", "resolve-from": "^5.0.0", @@ -18673,50 +18766,13 @@ "temp-dir": "^2.0.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "@expo/osascript": { + "version": "2.0.33", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.0.33.tgz", + "integrity": "sha512-FQinlwHrTlJbntp8a7NAlCKedVXe06Va/0DSLXRO8lZVtgbEMrYYSUZWQNcOlNtc58c2elNph6z9dMOYwSo3JQ==", "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@expo/config": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-7.0.3.tgz", - "integrity": "sha512-joVtB5o+NF40Tmsdp65UzryRtbnCuMbXkVO4wJnNJO4aaK0EYLdHCYSewORVqNcDfGN0LphQr8VTG2npbd9CJA==", - "requires": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~5.0.3", - "@expo/config-types": "^47.0.0", - "@expo/json-file": "8.2.36", - "getenv": "^1.0.0", - "glob": "7.1.6", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", - "semver": "7.3.2", - "slugify": "^1.3.4", - "sucrase": "^3.20.0" - } - }, - "@expo/config-types": { - "version": "47.0.0", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-47.0.0.tgz", - "integrity": "sha512-r0pWfuhkv7KIcXMUiNACJmJKKwlTBGMw9VZHNdppS8/0Nve8HZMTkNRFQzTHW1uH3pBj8jEXpyw/2vSWDHex9g==" - }, - "@expo/metro-config": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.5.2.tgz", - "integrity": "sha512-W1qsZPA5BXuRBkNLydKBYQ1+ubObhOK0gk2Fpc+XnhW+UUIHC9sDR5pZRYGNSnDDc3rG8y7c32UzSW9nlK+mog==", - "requires": { - "@expo/config": "~7.0.2", - "@expo/json-file": "8.2.36", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "find-yarn-workspace-root": "~2.0.0", - "getenv": "^1.0.0", - "resolve-from": "^5.0.0", - "sucrase": "^3.20.0" + "@expo/spawn-async": "^1.5.0", + "exec-async": "^2.2.0" } }, "ansi-styles": { @@ -18760,19 +18816,6 @@ "universalify": "^1.0.0" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -18788,9 +18831,9 @@ }, "dependencies": { "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" } } }, @@ -18815,9 +18858,9 @@ } }, "@expo/devcert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.0.0.tgz", - "integrity": "sha512-cahGyQCmpZmHpn2U04NR9KwsOIZy7Rhsw8Fg4q+A6563lIJxbkrgPnxq/O3NQAh3ohEvOXOOnoFx0b4yycCkpQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.1.0.tgz", + "integrity": "sha512-ghUVhNJQOCTdQckSGTHctNp/0jzvVoMMkVh+6SHn+TZj8sU15U/npXIDt8NtQp0HedlPaCgkVdMu8Sacne0aEA==", "requires": { "application-config-path": "^0.1.0", "command-exists": "^1.2.4", @@ -18831,7 +18874,7 @@ "rimraf": "^2.6.2", "sudo-prompt": "^8.2.0", "tmp": "^0.0.33", - "tslib": "^1.10.0" + "tslib": "^2.4.0" }, "dependencies": { "debug": { @@ -19014,9 +19057,9 @@ } }, "@expo/metro-config": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.3.22.tgz", - "integrity": "sha512-R81sLbaeUBjN8IXcxiVx7GcpSj8z7szILl1b5yJDb38WdIFwxhrseA5wXaTT1yMhI+59w6n99T2qtFV2yD5qYA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.4.0.tgz", + "integrity": "sha512-QhOiotuzklalLbbsTMXJ5v4q4jffQ5xXhy1zsosgc2DL/ZzUr/Yhm3xUcOGnPQ2x7UyeY9Tl3njPHBOJJe7CSA==", "requires": { "@expo/config": "7.0.1", "@expo/json-file": "8.2.36", @@ -19074,20 +19117,20 @@ } }, "@expo/osascript": { - "version": "2.0.33", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.0.33.tgz", - "integrity": "sha512-FQinlwHrTlJbntp8a7NAlCKedVXe06Va/0DSLXRO8lZVtgbEMrYYSUZWQNcOlNtc58c2elNph6z9dMOYwSo3JQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.1.0.tgz", + "integrity": "sha512-bOhuFnlRaS7CU33+rFFIWdcET/Vkyn1vsN8BYFwCDEF5P1fVVvYN7bFOsQLTMD3nvi35C1AGmtqUr/Wfv8Xaow==", "requires": { "@expo/spawn-async": "^1.5.0", "exec-async": "^2.2.0" } }, "@expo/package-manager": { - "version": "0.0.56", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-0.0.56.tgz", - "integrity": "sha512-PGk34uz4XDyhoNIlPh2D+BDsiXYuW2jXavTiax8d32uvHlRO6FN0cAsqlWD6fx3H2hRn8cU/leTuc4M7pYovCQ==", + "version": "0.0.60", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-0.0.60.tgz", + "integrity": "sha512-MdV7dpFA4aI8HIW0xsW2DBUem5aFKL8+/v5LXKPZuXmYW02/EXPSp7DBJAwow8ULpa3Q2VlYfb46hWPre3hw4A==", "requires": { - "@expo/json-file": "8.2.36", + "@expo/json-file": "^8.2.37", "@expo/spawn-async": "^1.5.0", "ansi-regex": "^5.0.0", "chalk": "^4.0.0", @@ -19099,6 +19142,24 @@ "sudo-prompt": "9.1.1" }, "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@expo/json-file": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz", + "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==", + "requires": { + "@babel/code-frame": "~7.10.4", + "json5": "^2.2.2", + "write-file-atomic": "^2.3.0" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -19422,9 +19483,9 @@ } }, "@expo/xcpretty": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.2.2.tgz", - "integrity": "sha512-Lke/geldJqUV0Dfxg5/QIOugOzdqZ/rQ9yHKSgGbjZtG1uiSqWyFwWvXmrdd3/sIdX33eykGvIcf+OrvvcXVUw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.3.1.tgz", + "integrity": "sha512-sqXgo1SCv+j4VtYEwl/bukuOIBrVgx6euIoCat3Iyx5oeoXwEA2USCoeL0IPubflMxncA2INkqJ/Wr3NGrSgzw==", "requires": { "@babel/code-frame": "7.10.4", "chalk": "^4.1.0", @@ -19504,9 +19565,9 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "@graphql-typed-document-node/core": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", "requires": {} }, "@hapi/hoek": { @@ -19744,9 +19805,9 @@ }, "dependencies": { "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "requires": { "lru-cache": "^6.0.0" } @@ -21201,9 +21262,12 @@ "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } }, "ansi-fragments": { "version": "0.2.1", @@ -21253,9 +21317,9 @@ "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==" }, "application-config-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/application-config-path/-/application-config-path-0.1.0.tgz", - "integrity": "sha512-lljTpVvFteShrHuKRvweZfa9o/Nc34Y8r5/1Lqh/yyKaspRT2J3fkEiSSk1YLG8ZSVyU7yHysRy9zcDDS2aH1Q==" + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/application-config-path/-/application-config-path-0.1.1.tgz", + "integrity": "sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==" }, "arg": { "version": "4.1.0", @@ -21321,13 +21385,6 @@ "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", "requires": { "tslib": "^2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - } } }, "astral-regex": { @@ -21646,24 +21703,27 @@ "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==" }, "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", + "bytes": "3.1.0", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", + "depd": "~1.1.2", + "http-errors": "1.7.2", "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -21672,23 +21732,42 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" } } }, @@ -21887,13 +21966,6 @@ "requires": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "camelcase": { @@ -22218,9 +22290,9 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "component-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", - "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.2.tgz", + "integrity": "sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==" }, "compressible": { "version": "2.0.18", @@ -22456,6 +22528,15 @@ "parse-json": "^4.0.0" } }, + "create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -22499,6 +22580,14 @@ "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", "requires": {} }, + "css-in-js-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", + "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "requires": { + "hyphenate-style-name": "^1.0.3" + } + }, "css-loader": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", @@ -22914,13 +23003,6 @@ "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "ee-first": { @@ -23239,24 +23321,24 @@ } }, "expo": { - "version": "46.0.9", - "resolved": "https://registry.npmjs.org/expo/-/expo-46.0.9.tgz", - "integrity": "sha512-UsBjm0BL7w+OyF6kypVPrk3jhg9cCXF0D9CaOWQ+cedm7oT4mTVQx9+A45VsDvLzNWBjJejZQZ1PFKqOY5HNcQ==", + "version": "46.0.21", + "resolved": "https://registry.npmjs.org/expo/-/expo-46.0.21.tgz", + "integrity": "sha512-leTI/GZXDN78xIThqimdK3Bk6uQ5dVkuWr+C0U/K0Ng5qDojQhJGtkM2lSS595KVTa3uYP6m0149MBg6Fp3fpA==", "requires": { "@babel/runtime": "^7.14.0", - "@expo/cli": "0.2.11", + "@expo/cli": "0.3.3", "@expo/vector-icons": "^13.0.0", "babel-preset-expo": "~9.2.0", "cross-spawn": "^6.0.5", "expo-application": "~4.2.2", - "expo-asset": "~8.6.1", + "expo-asset": "~8.6.3", "expo-constants": "~13.2.4", "expo-error-recovery": "~3.2.0", "expo-file-system": "~14.1.0", - "expo-font": "~10.2.0", + "expo-font": "~10.2.1", "expo-keep-awake": "~10.2.0", "expo-modules-autolinking": "0.10.3", - "expo-modules-core": "0.11.4", + "expo-modules-core": "0.11.10", "fbemitter": "^3.0.0", "getenv": "^1.0.0", "invariant": "^2.2.4", @@ -23273,9 +23355,9 @@ "requires": {} }, "expo-asset": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.6.1.tgz", - "integrity": "sha512-urbUp1YtwH2J0Qc3inGQJdqTjWKML77SeMNgff+iR9MUE8gDkFqSCDjrBi7i5Oj5DDtq43mmtDg8G8ei6Vchcg==", + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.6.3.tgz", + "integrity": "sha512-AOuB0FBbwYUfuLKtQtIsKUvm08d9OAPWZu9NZjUyIvAxmmdVKPUdN5tFUZQXXLRy3SYmk2z76JVQCoaHgJ5wvw==", "requires": { "blueimp-md5": "^2.10.0", "expo-constants": "~13.2.2", @@ -23312,9 +23394,9 @@ } }, "expo-font": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-10.2.0.tgz", - "integrity": "sha512-2V4EcpmhNoppaLn+lPprZVS+3bmV9hxLPKttKh2u8ghjH/oX9bv3u4JVo77SYh0EfrWO4toqVyXn8pXH8GpbIg==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-10.2.1.tgz", + "integrity": "sha512-sxy5GrdtY+Ka8Wo5wnrcFFeO6MbYC6Dris5wMLqshvVK6BneJNMUsFvwRfvVgg0TzsmMAc3Rlca2xyZ8ettinw==", "requires": { "fontfaceobserver": "^2.1.0" } @@ -23408,9 +23490,9 @@ } }, "expo-modules-core": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-0.11.4.tgz", - "integrity": "sha512-8dEYICk7hUi1GPz5hWm8dBuZDGc+4Tm7zDhSIhKApo5jY/5vB4Bk+fjPo693iWn6pp3+XBHT8Ri8rJ3G7wH1vQ==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-0.11.10.tgz", + "integrity": "sha512-wn7bdL1AXMNuuDEFhuIeE65A+dlvBL+6nC5fGy4NO7x3TXPBR1xCgL28i8d8WWyK5evI4z4TVvJp3YYzdapbqQ==", "requires": { "compare-versions": "^3.4.0", "invariant": "^2.2.4" @@ -23788,6 +23870,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "fast-loops": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz", + "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==" + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -24126,13 +24213,6 @@ "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", "requires": { "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - } } }, "handle-thing": { @@ -24402,6 +24482,11 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -24476,6 +24561,15 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "inline-style-prefixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz", + "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==", + "requires": { + "css-in-js-utils": "^3.1.0", + "fast-loops": "^1.1.3" + } + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -25409,13 +25503,6 @@ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "requires": { "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "lru-cache": { @@ -26066,9 +26153,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "requires": { "yallist": "^4.0.0" } @@ -26243,13 +26330,6 @@ "requires": { "lower-case": "^2.0.2", "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "nocache": { @@ -26307,6 +26387,11 @@ "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==" }, + "normalize-css-color": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/normalize-css-color/-/normalize-css-color-1.0.2.tgz", + "integrity": "sha512-jPJ/V7Cp1UytdidsPqviKEElFQJs22hUUgK5BOPHTwOonNCk7/2qOxhhqzEajmFrWJowADFfOFh1V+aWkRfy+w==" + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -26595,13 +26680,6 @@ "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "parse-json": { @@ -26633,13 +26711,6 @@ "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } } }, "pascalcase": { @@ -26648,12 +26719,50 @@ "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" }, "password-prompt": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", - "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", + "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==", "requires": { - "ansi-escapes": "^3.1.0", - "cross-spawn": "^6.0.5" + "ansi-escapes": "^4.3.2", + "cross-spawn": "^7.0.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } } }, "path-browserify": { @@ -27286,14 +27395,48 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", + "bytes": "3.1.0", + "http-errors": "1.7.2", "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + } } }, "rc": { @@ -27347,9 +27490,9 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-native": { - "version": "0.69.5", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.69.5.tgz", - "integrity": "sha512-4Psrj1nDMLQjBXVH8n3UikzOHQc8+sa6NbxZQR0XKtpx8uC3HiJBgX+/FIum/RWxfi5J/Dt/+A2gLGmq2Hps8g==", + "version": "0.69.9", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.69.9.tgz", + "integrity": "sha512-I1xqIn47RWxBToO4E6yqyIPSaK9mZnMiscMfrFpWjQr3Gdkicr9y+twmtrRszxaLdQLjHzh/M3y4qOqc3hZnpg==", "requires": { "@jest/create-cache-key-function": "^27.0.1", "@react-native-community/cli": "^8.0.4", @@ -27372,7 +27515,7 @@ "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", - "promise": "^8.0.3", + "promise": "^8.2.0", "react-devtools-core": "4.24.0", "react-native-codegen": "^0.69.2", "react-native-gradle-plugin": "^0.0.7", @@ -27387,9 +27530,9 @@ }, "dependencies": { "promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", "requires": { "asap": "~2.0.6" } @@ -27530,6 +27673,20 @@ } } }, + "react-native-web": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.12.tgz", + "integrity": "sha512-fboP7yqobJ8InSr4fP+bQ3scOtSQtUoPcR+HWasH8b/fk/RO+mWcJs/8n+lewy9WTZc2D68ha7VwRDviUshEWA==", + "requires": { + "@babel/runtime": "^7.18.6", + "create-react-class": "^15.7.0", + "fbjs": "^3.0.4", + "inline-style-prefixer": "^6.0.1", + "normalize-css-color": "^1.0.2", + "postcss-value-parser": "^4.2.0", + "styleq": "^0.1.2" + } + }, "react-refresh": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", @@ -27580,13 +27737,6 @@ "esprima": "~4.0.0", "source-map": "~0.6.1", "tslib": "^2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - } } }, "regenerate": { @@ -27957,6 +28107,13 @@ "integrity": "sha512-3vmBkMZLQO+BR4RPHcyRGdE09XCF6cvxzk2N2qn8Er3F91cy8Qt7VvEbZBOpaL53qsBbe2cFOefU6tRY6WDelA==", "requires": { "type-fest": "^0.12.0" + }, + "dependencies": { + "type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==" + } } }, "serialize-javascript": { @@ -28647,6 +28804,11 @@ "postcss-selector-parser": "^6.0.4" } }, + "styleq": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz", + "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==" + }, "sucrase": { "version": "3.25.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz", @@ -28694,9 +28856,9 @@ } }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "requires": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -28742,18 +28904,23 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, "dependencies": { + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -28833,21 +29000,6 @@ "requires": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "requires": { - "type-fest": "^0.21.3" - } - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - } } }, "terser": { @@ -29003,9 +29155,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==" + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==" }, "ts-interface-checker": { "version": "0.1.13", @@ -29013,9 +29165,9 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "type": { "version": "1.2.0", @@ -29023,9 +29175,9 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, "type-fest": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", - "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==" + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, "type-is": { "version": "1.6.18", diff --git a/examples/user-management/expo-user-management/package.json b/examples/user-management/expo-user-management/package.json index cc1de90383f..c229147e9a7 100644 --- a/examples/user-management/expo-user-management/package.json +++ b/examples/user-management/expo-user-management/package.json @@ -3,6 +3,7 @@ "version": "2.0.0", "scripts": { "start": "expo start --dev-client", + "prebuild": "expo prebuild", "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web", @@ -12,15 +13,16 @@ "@expo/webpack-config": "^18.0.3", "@react-native-async-storage/async-storage": "^1.17.9", "@supabase/supabase-js": "^2.0.4", - "expo": "~46.0.9", + "expo": "~46.0.21", "expo-splash-screen": "~0.16.2", "expo-status-bar": "~1.4.0", "react": "18.0.0", "react-dom": "18.0.0", - "react-native": "0.69.5", + "react-native": "0.69.9", "react-native-document-picker": "^8.1.1", "react-native-elements": "^3.4.2", - "react-native-url-polyfill": "^1.3.0" + "react-native-url-polyfill": "^1.3.0", + "react-native-web": "~0.18.7" }, "devDependencies": { "@babel/core": "^7.12.9", diff --git a/examples/user-management/expo-user-management/supabase/.gitignore b/examples/user-management/expo-user-management/supabase/.gitignore new file mode 100644 index 00000000000..a3ad88055b7 --- /dev/null +++ b/examples/user-management/expo-user-management/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/examples/user-management/expo-user-management/supabase/config.toml b/examples/user-management/expo-user-management/supabase/config.toml new file mode 100644 index 00000000000..eada7f61cc3 --- /dev/null +++ b/examples/user-management/expo-user-management/supabase/config.toml @@ -0,0 +1,161 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "expo-user-management" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +[auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" + +[analytics] +enabled = false +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql b/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql new file mode 100644 index 00000000000..7c102c555fa --- /dev/null +++ b/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql @@ -0,0 +1,53 @@ +-- Create a table for public profiles +create table profiles ( + id uuid references auth.users not null primary key, + updated_at timestamp with time zone, + username text unique, + full_name text, + avatar_url text, + website text, + + constraint username_length check (char_length(username) >= 3) +); +-- Set up Row Level Security (RLS) +-- See https://supabase.com/docs/guides/auth/row-level-security for more details. +alter table profiles + enable row level security; + +create policy "Public profiles are viewable by everyone." on profiles + for select using (true); + +create policy "Users can insert their own profile." on profiles + for insert with check (auth.uid() = id); + +create policy "Users can update own profile." on profiles + for update using (auth.uid() = id); + +-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth. +-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details. +create function public.handle_new_user() +returns trigger as $$ +begin + insert into public.profiles (id, full_name, avatar_url) + values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); + return new; +end; +$$ language plpgsql security definer; +create trigger on_auth_user_created + after insert on auth.users + for each row execute procedure public.handle_new_user(); + +-- Set up Storage! +insert into storage.buckets (id, name) + values ('avatars', 'avatars'); + +-- Set up access controls for storage. +-- See https://supabase.com/docs/guides/storage#policy-examples for more details. +create policy "Avatar images are publicly accessible." on storage.objects + for select using (bucket_id = 'avatars'); + +create policy "Anyone can upload an avatar." on storage.objects + for insert with check (bucket_id = 'avatars'); + +create policy "Anyone can update their own avatar." on storage.objects + for update using ( auth.uid() = owner ) with check (bucket_id = 'avatars'); diff --git a/examples/user-management/expo-user-management/supabase/seed.sql b/examples/user-management/expo-user-management/supabase/seed.sql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/user-management/flutter-user-management/.env.example b/examples/user-management/flutter-user-management/.env.example new file mode 100644 index 00000000000..4956a099f8f --- /dev/null +++ b/examples/user-management/flutter-user-management/.env.example @@ -0,0 +1,2 @@ +SUPABASE_URL=https://mysupabasereference.supabase.co +SUPABASE_ANON_KEY=my.supabase.anon.key \ No newline at end of file diff --git a/examples/user-management/flutter-user-management/.gitignore b/examples/user-management/flutter-user-management/.gitignore index 6d47c6f3495..48ecadddce0 100644 --- a/examples/user-management/flutter-user-management/.gitignore +++ b/examples/user-management/flutter-user-management/.gitignore @@ -45,3 +45,5 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +.env \ No newline at end of file diff --git a/examples/user-management/flutter-user-management/README.md b/examples/user-management/flutter-user-management/README.md index 38f7169d129..89b8faf3215 100644 --- a/examples/user-management/flutter-user-management/README.md +++ b/examples/user-management/flutter-user-management/README.md @@ -1,8 +1,9 @@ # Supabase Flutter User Management -This repo is a quick sample of how you can get started building apps using Flutter and Supabase. You can find a step by step guide of how to build out this app in the [Quickstart: Flutter guide](https://supabase.io/docs/guides/with-flutter). +This repo is a quick sample of how you can get started building apps using Flutter and Supabase. You can find a step by step guide of how to build out this app in the [Quickstart: Flutter guide](https://supabase.io/docs/guides/with-flutter). This repo will demonstrate how to: + - sign users in with Supabase Auth using [magic link](https://supabase.io/docs/reference/dart/auth-signin#sign-in-with-magic-link) - store and retrieve data with [Supabase database](https://supabase.io/docs/guides/database) - store image files in [Supabase storage](https://supabase.io/docs/guides/storage) @@ -11,16 +12,18 @@ This repo will demonstrate how to: ## Getting Started -Before running this app, you need to create a Supabase project and copy [your credentials](https://supabase.io/docs/guides/with-flutter#get-the-api-keys) to `main.dart`. +Rename `.env.example` to `.env` and fill in [your Supabase credentials](https://supabase.io/docs/guides/with-flutter#get-the-api-keys). -You can run this app on iOS, Android or the Web. +You can run this app on iOS, Android or the Web. To run this application, simply run the following for iOS or Android + ```bash flutter run ``` Or for web, run the following command to launch it on `localhost:3000` + ```bash flutter run -d web-server --web-hostname localhost --web-port 3000 ``` @@ -73,4 +76,4 @@ create policy "Avatar images are publicly accessible." create policy "Anyone can upload an avatar." on storage.objects for insert with check ( bucket_id = 'avatars' ); -``` \ No newline at end of file +``` diff --git a/examples/user-management/flutter-user-management/lib/main.dart b/examples/user-management/flutter-user-management/lib/main.dart index 656b7e22257..023d4f87eb4 100644 --- a/examples/user-management/flutter-user-management/lib/main.dart +++ b/examples/user-management/flutter-user-management/lib/main.dart @@ -1,14 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_quickstart/pages/account_page.dart'; import 'package:supabase_quickstart/pages/login_page.dart'; import 'package:supabase_quickstart/pages/splash_page.dart'; Future main() async { + await dotenv.load(); + await Supabase.initialize( - // TODO: Replace credentials with your own - url: 'YOUR_SUPABASE_URL', - anonKey: 'YOUR_SUPABASE_ANON_KEY', + url: dotenv.env['SUPABASE_URL']!, + anonKey: dotenv.env['SUPABASE_ANON_KEY']!, ); runApp(MyApp()); } diff --git a/examples/user-management/flutter-user-management/pubspec.yaml b/examples/user-management/flutter-user-management/pubspec.yaml index 86dbeaae266..a255f93a88b 100644 --- a/examples/user-management/flutter-user-management/pubspec.yaml +++ b/examples/user-management/flutter-user-management/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: flutter: sdk: flutter + flutter_dotenv: ^5.1.0 image_picker: ^1.0.5 supabase_flutter: ^2.0.0 @@ -22,3 +23,5 @@ dev_dependencies: flutter: uses-material-design: true + assets: + - .env diff --git a/examples/user-management/flutter-user-management/supabase/.gitignore b/examples/user-management/flutter-user-management/supabase/.gitignore new file mode 100644 index 00000000000..a3ad88055b7 --- /dev/null +++ b/examples/user-management/flutter-user-management/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/examples/user-management/flutter-user-management/supabase/config.toml b/examples/user-management/flutter-user-management/supabase/config.toml new file mode 100644 index 00000000000..29eb2b255d6 --- /dev/null +++ b/examples/user-management/flutter-user-management/supabase/config.toml @@ -0,0 +1,161 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "flutter-user-management" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +[auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" + +[analytics] +enabled = false +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/examples/user-management/flutter-user-management/supabase/migrations/20240404030631_init.sql b/examples/user-management/flutter-user-management/supabase/migrations/20240404030631_init.sql new file mode 100644 index 00000000000..6d3cce93b4e --- /dev/null +++ b/examples/user-management/flutter-user-management/supabase/migrations/20240404030631_init.sql @@ -0,0 +1,45 @@ +-- Create a table for public "profiles" +create table profiles ( + id uuid references auth.users not null, + updated_at timestamp with time zone, + username text unique, + avatar_url text, + website text, + + primary key (id), + unique(username), + constraint username_length check (char_length(username) >= 3) +); + +alter table profiles enable row level security; + +create policy "Public profiles are viewable by everyone." + on profiles for select + using ( true ); + +create policy "Users can insert their own profile." + on profiles for insert + with check ( auth.uid() = id ); + +create policy "Users can update own profile." + on profiles for update + using ( auth.uid() = id ); + +-- Set up Realtime! +begin; + drop publication if exists supabase_realtime; + create publication supabase_realtime; +commit; +alter publication supabase_realtime add table profiles; + +-- Set up Storage! +insert into storage.buckets (id, name) +values ('avatars', 'avatars'); + +create policy "Avatar images are publicly accessible." + on storage.objects for select + using ( bucket_id = 'avatars' ); + +create policy "Anyone can upload an avatar." + on storage.objects for insert + with check ( bucket_id = 'avatars' ); \ No newline at end of file diff --git a/examples/user-management/flutter-user-management/supabase/seed.sql b/examples/user-management/flutter-user-management/supabase/seed.sql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/user-management/nextjs-user-management/.env.example b/examples/user-management/nextjs-user-management/.env.example new file mode 100644 index 00000000000..e3a1289f58d --- /dev/null +++ b/examples/user-management/nextjs-user-management/.env.example @@ -0,0 +1,4 @@ +# Get these from your API settings: https://supabase.com/dashboard/project/_/settings/api + +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/examples/user-management/swift-user-management/.env.example b/examples/user-management/swift-user-management/.env.example new file mode 100644 index 00000000000..f9345e27e65 --- /dev/null +++ b/examples/user-management/swift-user-management/.env.example @@ -0,0 +1,4 @@ +# Get these from your API settings: https://supabase.com/dashboard/project/_/settings/api + +SUPABASE_URL=https://mysupabasereference.supabase.co +SUPABASE_ANON_KEY=my.supabase.anon.key \ No newline at end of file diff --git a/examples/user-management/swift-user-management/.gitignore b/examples/user-management/swift-user-management/.gitignore index b5bafa0d145..0e9eda37cbb 100644 --- a/examples/user-management/swift-user-management/.gitignore +++ b/examples/user-management/swift-user-management/.gitignore @@ -132,3 +132,6 @@ iOSInjectionProject/ **/xcshareddata/WorkspaceSettings.xcsettings # End of https://www.toptal.com/developers/gitignore/api/xcode,swift,macos + +.env +DotEnv.swift \ No newline at end of file diff --git a/examples/user-management/swift-user-management/README.md b/examples/user-management/swift-user-management/README.md index 17e736b201c..54df3af9f58 100644 --- a/examples/user-management/swift-user-management/README.md +++ b/examples/user-management/swift-user-management/README.md @@ -11,7 +11,7 @@ This repo will demonstrate how to: ## Getting Started -Before running this app, you need to create a Supabase project and copy [your credentials](https://supabase.io/docs/guides/with-flutter#get-the-api-keys) to `Supabase.swift`. +Run `cp .env.example .env` and fill in [your credentials](https://supabase.io/docs/guides/with-flutter#get-the-api-keys). Run the application in a device or simulator using Xcode. diff --git a/examples/user-management/swift-user-management/scripts/dotenv.sh b/examples/user-management/swift-user-management/scripts/dotenv.sh new file mode 100755 index 00000000000..88cef004416 --- /dev/null +++ b/examples/user-management/swift-user-management/scripts/dotenv.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +env_file="${1:-.env}" + +if [[ -f "$env_file" ]]; then + echo "enum DotEnv {" + while IFS='=' read -r key value || [[ -n "$key" ]]; do + if [[ -n "$key" && ! "$key" =~ ^# ]]; then + if [[ -z "$value" ]]; then + value=$(eval "echo \$$key") + fi + echo " static let $key = \"$value\"" + fi + done < <(grep -v '^#' "$env_file") + echo "}" +fi diff --git a/examples/user-management/swift-user-management/supabase/.gitignore b/examples/user-management/swift-user-management/supabase/.gitignore new file mode 100644 index 00000000000..a3ad88055b7 --- /dev/null +++ b/examples/user-management/swift-user-management/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/examples/user-management/swift-user-management/supabase/config.toml b/examples/user-management/swift-user-management/supabase/config.toml new file mode 100644 index 00000000000..746cb812b55 --- /dev/null +++ b/examples/user-management/swift-user-management/supabase/config.toml @@ -0,0 +1,161 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "swift-user-management" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +[auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" + +[analytics] +enabled = false +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql b/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql new file mode 100644 index 00000000000..7c102c555fa --- /dev/null +++ b/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql @@ -0,0 +1,53 @@ +-- Create a table for public profiles +create table profiles ( + id uuid references auth.users not null primary key, + updated_at timestamp with time zone, + username text unique, + full_name text, + avatar_url text, + website text, + + constraint username_length check (char_length(username) >= 3) +); +-- Set up Row Level Security (RLS) +-- See https://supabase.com/docs/guides/auth/row-level-security for more details. +alter table profiles + enable row level security; + +create policy "Public profiles are viewable by everyone." on profiles + for select using (true); + +create policy "Users can insert their own profile." on profiles + for insert with check (auth.uid() = id); + +create policy "Users can update own profile." on profiles + for update using (auth.uid() = id); + +-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth. +-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details. +create function public.handle_new_user() +returns trigger as $$ +begin + insert into public.profiles (id, full_name, avatar_url) + values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); + return new; +end; +$$ language plpgsql security definer; +create trigger on_auth_user_created + after insert on auth.users + for each row execute procedure public.handle_new_user(); + +-- Set up Storage! +insert into storage.buckets (id, name) + values ('avatars', 'avatars'); + +-- Set up access controls for storage. +-- See https://supabase.com/docs/guides/storage#policy-examples for more details. +create policy "Avatar images are publicly accessible." on storage.objects + for select using (bucket_id = 'avatars'); + +create policy "Anyone can upload an avatar." on storage.objects + for insert with check (bucket_id = 'avatars'); + +create policy "Anyone can update their own avatar." on storage.objects + for update using ( auth.uid() = owner ) with check (bucket_id = 'avatars'); diff --git a/examples/user-management/swift-user-management/supabase/seed.sql b/examples/user-management/swift-user-management/supabase/seed.sql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.pbxproj b/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.pbxproj index 7de374bff07..6d55da3c2ad 100644 --- a/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.pbxproj +++ b/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 7922C77F2BBED449007F611D /* DotEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7922C77E2BBED449007F611D /* DotEnv.swift */; }; 79A039A22B2B89FF0031D573 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79A039A12B2B89FF0031D573 /* Assets.xcassets */; }; 79A039A52B2B89FF0031D573 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79A039A42B2B89FF0031D573 /* Preview Assets.xcassets */; }; 79A039B62B2B8A6F0031D573 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79A039AB2B2B8A6E0031D573 /* Models.swift */; }; @@ -21,6 +22,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 7922C77E2BBED449007F611D /* DotEnv.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DotEnv.swift; sourceTree = ""; }; 79A0399A2B2B89FF0031D573 /* swift-user-management.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "swift-user-management.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 79A039A12B2B89FF0031D573 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 79A039A42B2B89FF0031D573 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; @@ -69,6 +71,7 @@ 79A039B22B2B8A6F0031D573 /* AppView.swift */, 79A039A12B2B89FF0031D573 /* Assets.xcassets */, 79A039B42B2B8A6F0031D573 /* AuthView.swift */, + 7922C77E2BBED449007F611D /* DotEnv.swift */, 79A039AC2B2B8A6F0031D573 /* AvatarImage.swift */, 79A039C32B2B8B0A0031D573 /* Info.plist */, 79A039AB2B2B8A6E0031D573 /* Models.swift */, @@ -96,6 +99,7 @@ isa = PBXNativeTarget; buildConfigurationList = 79A039A82B2B89FF0031D573 /* Build configuration list for PBXNativeTarget "swift-user-management" */; buildPhases = ( + 7922C77D2BBED225007F611D /* ShellScript */, 79A039962B2B89FF0031D573 /* Sources */, 79A039972B2B89FF0031D573 /* Frameworks */, 79A039982B2B89FF0031D573 /* Resources */, @@ -160,6 +164,29 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 7922C77D2BBED225007F611D /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/scripts/dotenv.sh", + "${SRCROOT}/.env", + ); + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/swift-user-management/DotEnv.swift", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n${SRCROOT}/scripts/dotenv.sh ${SRCROOT}/.env > ${SRCROOT}/swift-user-management/DotEnv.swift\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 79A039962B2B89FF0031D573 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -170,6 +197,7 @@ 79A039B92B2B8A6F0031D573 /* Supabase.swift in Sources */, 79A039BC2B2B8A6F0031D573 /* SwiftUIHelpers.swift in Sources */, 79A039B72B2B8A6F0031D573 /* AvatarImage.swift in Sources */, + 7922C77F2BBED449007F611D /* DotEnv.swift in Sources */, 79A039BD2B2B8A6F0031D573 /* AppView.swift in Sources */, 79A039BE2B2B8A6F0031D573 /* AuthView.swift in Sources */, 79A039BA2B2B8A6F0031D573 /* UserManagementApp.swift in Sources */, diff --git a/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9c2c8179493..9921469c9c0 100644 --- a/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/examples/user-management/swift-user-management/swift-user-management.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "a2b47b975283c007063016d75469b395d89f8763da1d376160fb8c6dcfdb6109", "pins" : [ { "identity" : "keychainaccess", @@ -14,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/supabase-community/supabase-swift", "state" : { - "revision" : "036c03d4862bd93f4d93c88f9a365dc292abb74f", - "version" : "2.0.0" + "revision" : "1a7dad006f94749923e764343aaaeadbe74f0352", + "version" : "2.6.0" } }, { @@ -26,7 +27,16 @@ "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", "version" : "1.1.0" } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", + "version" : "3.3.0" + } } ], - "version" : 2 + "version" : 3 } diff --git a/examples/user-management/swift-user-management/swift-user-management/Supabase.swift b/examples/user-management/swift-user-management/swift-user-management/Supabase.swift index c76a5509f8f..716171bbd52 100644 --- a/examples/user-management/swift-user-management/swift-user-management/Supabase.swift +++ b/examples/user-management/swift-user-management/swift-user-management/Supabase.swift @@ -9,6 +9,6 @@ import Foundation import Supabase let supabase = SupabaseClient( - supabaseURL: URL(string: "https://PROJECT_ID.supabase.co")!, - supabaseKey: "YOUR_SUPABASE_ANON_KEY" + supabaseURL: URL(string: DotEnv.SUPABASE_URL)!, + supabaseKey: DotEnv.SUPABASE_ANON_KEY ) diff --git a/package-lock.json b/package-lock.json index 0eb1940d320..455cfb81d37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "prettier-plugin-sql-cst": "^0.11.0", "sass": "^1.72.0", "supabase": "^1.151.1", - "turbo": "^1.13.0" + "turbo": "^1.13.2" }, "engines": { "node": ">=20.0.0", @@ -42,10 +42,10 @@ "common": "*", "config": "*", "dayjs": "^1.11.10", - "eslint-config-next": "^14.1.0", + "eslint-config-next": "^14.1.4", "lodash": "^4.17.21", "lucide-react": "^0.338.0", - "next": "^14.0.3", + "next": "^14.1.4", "openai": "^4.20.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -61,15 +61,15 @@ "@types/react": "^18.2.24", "@types/react-dom": "^18.2.8", "autoprefixer": "^10.4.14", - "nextjs-node-loader": "^1.1.5-alpha.0", + "nextjs-node-loader": "^1.1.5", "postcss": "^8.4.31", "typescript": "^5.4.3" } }, "apps/database-new/node_modules/@next/eslint-plugin-next": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz", - "integrity": "sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.4.tgz", + "integrity": "sha512-n4zYNLSyCo0Ln5b7qxqQeQ34OZKXwgbdcx6kmkQbywr+0k6M3Vinft0T72R6CDAcDrne2IAgSud4uWCzFgc5HA==", "dependencies": { "glob": "10.3.10" } @@ -115,11 +115,11 @@ } }, "apps/database-new/node_modules/eslint-config-next": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.0.tgz", - "integrity": "sha512-SBX2ed7DoRFXC6CQSLc/SbLY9Ut6HxNB2wPTcoIWjUMd7aF7O/SIE7111L8FdZ9TXsNV4pulUDnfthpyPtbFUg==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.4.tgz", + "integrity": "sha512-cihIahbhYAWwXJwZkAaRPpUi5t9aOi/HdfWXOjZeUOqNWXHD8X22kd1KG58Dc3MVaRx3HoR/oMGk2ltcrqDn8g==", "dependencies": { - "@next/eslint-plugin-next": "14.1.0", + "@next/eslint-plugin-next": "14.1.4", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", @@ -227,15 +227,15 @@ "@code-hike/mdx": "^0.9.0", "@mdx-js/loader": "^2.1.5", "@mdx-js/react": "^2.3.0", - "@next/bundle-analyzer": "^13.5.6", - "@next/mdx": "^13.5.6", + "@next/bundle-analyzer": "^14.1.4", + "@next/mdx": "^14.1.4", "@octokit/auth-app": "^6.0.3", - "@octokit/core": "^5.0.2", + "@octokit/core": "^5.1.0", "@octokit/graphql": "^7.0.2", "@octokit/plugin-paginate-graphql": "^4.0.0", "@radix-ui/react-accordion": "^1.1.2", "@supabase/auth-helpers-react": "^0.4.2", - "@supabase/supabase-js": "^2.39.3", + "@supabase/supabase-js": "^2.41.1", "@tailwindcss/container-queries": "^0.1.1", "@tanstack/react-query": "^5.13.4", "common": "*", @@ -259,11 +259,11 @@ "mdx-mermaid": "2.0.0-rc3", "mermaid": "^10.0.2", "micromark-extension-mdxjs": "^1.0.0", - "next": "^13.4.8", + "next": "^14.1.4", "next-mdx-remote": "^4.4.1", "next-plugin-yaml": "^1.0.1", "next-seo": "^6.5.0", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "openai": "^4.20.1", "openapi-fetch": "^0.8.2", "react": "^18.2.0", @@ -307,154 +307,6 @@ "typescript": "^5.4.3" } }, - "apps/docs/node_modules/@next/env": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.8.tgz", - "integrity": "sha512-twuSf1klb3k9wXI7IZhbZGtFCWvGD4wXTY2rmvzIgVhXhs7ISThrbNyutBx3jWIL8Y/Hk9+woytFz5QsgtcRKQ==" - }, - "apps/docs/node_modules/@next/swc-darwin-arm64": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.8.tgz", - "integrity": "sha512-MSFplVM4dTWOuKAUv0XR9gY7AWtMSBu9os9f+kp+s5rWhM1I2CdR3obFttd6366nS/W/VZxbPM5oEIdlIa46zA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-darwin-x64": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.8.tgz", - "integrity": "sha512-Reox+UXgonon9P0WNDE6w85DGtyBqGitl/ryznOvn6TvfxEaZIpTgeu3ZrJLU9dHSMhiK7YAM793mE/Zii2/Qw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.8.tgz", - "integrity": "sha512-kdyzYvAYtqQVgzIKNN7e1rLU8aZv86FDSRqPlOkKZlvqudvTO0iohuTPmnEEDlECeBM6qRPShNffotDcU/R2KA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.8.tgz", - "integrity": "sha512-oWxx4yRkUGcR81XwbI+T0zhZ3bDF6V1aVLpG+C7hSG50ULpV8gC39UxVO22/bv93ZlcfMY4zl8xkz9Klct6dpQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.8.tgz", - "integrity": "sha512-anhtvuO6eE9YRhYnaEGTfbpH3L5gT/9qPFcNoi6xS432r/4DAtpJY8kNktqkTVevVIC/pVumqO8tV59PR3zbNg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.8.tgz", - "integrity": "sha512-aR+J4wWfNgH1DwCCBNjan7Iumx0lLtn+2/rEYuhIrYLY4vnxqSVGz9u3fXcgUwo6Q9LT8NFkaqK1vPprdq+BXg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.8.tgz", - "integrity": "sha512-OWBKIrJwQBTqrat0xhxEB/jcsjJR3+diD9nc/Y8F1mRdQzsn4bPsomgJyuqPVZs6Lz3K18qdIkvywmfSq75SsQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.8.tgz", - "integrity": "sha512-agiPWGjUndXGTOn4ChbKipQXRA6/UPkywAWIkx7BhgGv48TiJfHTK6MGfBoL9tS6B4mtW39++uy0wFPnfD0JWg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.8.tgz", - "integrity": "sha512-UIRKoByVKbuR6SnFG4JM8EMFlJrfEGuUQ1ihxzEleWcNwRMMiVaCj1KyqfTOW8VTQhJ0u8P1Ngg6q1RwnIBTtw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/docs/node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "dependencies": { - "tslib": "^2.4.0" - } - }, "apps/docs/node_modules/@tanstack/query-core": { "version": "5.13.4", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.13.4.tgz", @@ -586,79 +438,6 @@ ], "license": "MIT" }, - "apps/docs/node_modules/next": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.8.tgz", - "integrity": "sha512-lxUjndYKjZHGK3CWeN2RI+/6ni6EUvjiqGWXAYPxUfGIdFGQ5XoisrqAJ/dF74aP27buAfs8MKIbIMMdxjqSBg==", - "dependencies": { - "@next/env": "13.4.8", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0", - "zod": "3.21.4" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=16.8.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.8", - "@next/swc-darwin-x64": "13.4.8", - "@next/swc-linux-arm64-gnu": "13.4.8", - "@next/swc-linux-arm64-musl": "13.4.8", - "@next/swc-linux-x64-gnu": "13.4.8", - "@next/swc-linux-x64-musl": "13.4.8", - "@next/swc-win32-arm64-msvc": "13.4.8", - "@next/swc-win32-ia32-msvc": "13.4.8", - "@next/swc-win32-x64-msvc": "13.4.8" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "fibers": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "apps/docs/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "apps/docs/node_modules/puppeteer": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-16.2.0.tgz", @@ -744,14 +523,6 @@ } } }, - "apps/docs/node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "apps/docs/spec/parser": { "name": "@supabase/generator", "version": "0.0.0", @@ -2335,17 +2106,18 @@ "@hcaptcha/react-hcaptcha": "^1.8.1", "@headlessui/react": "^1.7.17", "@monaco-editor/react": "^4.6.0", - "@next/bundle-analyzer": "^13.5.6", + "@next/bundle-analyzer": "^14.1.4", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7", "@scaleleap/pg-format": "^1.0.0", - "@sentry/nextjs": "^7.77.0", + "@sentry/nextjs": "^7.108.0", "@serafin/schema-builder": "^0.18.2", "@stripe/react-stripe-js": "^2.5.0", "@stripe/stripe-js": "^3.0.5", "@supabase/auth-helpers-react": "^0.4.2", + "@supabase/pg-meta": "*", "@supabase/shared-types": "0.1.55", - "@supabase/supabase-js": "^2.39.3", + "@supabase/supabase-js": "^2.41.1", "@tanstack/react-query": "4.35.7", "@tanstack/react-query-devtools": "4.35.7", "@uidotdev/usehooks": "^2.4.1", @@ -2375,8 +2147,8 @@ "mobx": "^6.10.2", "mobx-react-lite": "^4.0.5", "monaco-editor": "0.33.0", - "next": "^13.5.6", - "next-themes": "^0.2.1", + "next": "^14.1.4", + "next-themes": "^0.3.0", "openai": "^4.20.1", "openapi-fetch": "^0.6.2", "p-queue": "^6.6.2", @@ -2451,7 +2223,7 @@ "autoprefixer": "^10.4.14", "common": "*", "config": "*", - "eslint-config-next": "^14.1.0", + "eslint-config-next": "^14.1.4", "jest": "^29.7.0", "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.7.0", @@ -2480,155 +2252,15 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "apps/studio/node_modules/@next/env": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", - "integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==" - }, "apps/studio/node_modules/@next/eslint-plugin-next": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz", - "integrity": "sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.4.tgz", + "integrity": "sha512-n4zYNLSyCo0Ln5b7qxqQeQ34OZKXwgbdcx6kmkQbywr+0k6M3Vinft0T72R6CDAcDrne2IAgSud4uWCzFgc5HA==", "dev": true, "dependencies": { "glob": "10.3.10" } }, - "apps/studio/node_modules/@next/swc-darwin-arm64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz", - "integrity": "sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-darwin-x64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz", - "integrity": "sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz", - "integrity": "sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-linux-arm64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz", - "integrity": "sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-linux-x64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz", - "integrity": "sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-linux-x64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz", - "integrity": "sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz", - "integrity": "sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz", - "integrity": "sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/studio/node_modules/@next/swc-win32-x64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz", - "integrity": "sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "apps/studio/node_modules/@storybook/addon-backgrounds": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.17.tgz", @@ -3553,12 +3185,12 @@ } }, "apps/studio/node_modules/eslint-config-next": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.0.tgz", - "integrity": "sha512-SBX2ed7DoRFXC6CQSLc/SbLY9Ut6HxNB2wPTcoIWjUMd7aF7O/SIE7111L8FdZ9TXsNV4pulUDnfthpyPtbFUg==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.4.tgz", + "integrity": "sha512-cihIahbhYAWwXJwZkAaRPpUi5t9aOi/HdfWXOjZeUOqNWXHD8X22kd1KG58Dc3MVaRx3HoR/oMGk2ltcrqDn8g==", "dev": true, "dependencies": { - "@next/eslint-plugin-next": "14.1.0", + "@next/eslint-plugin-next": "14.1.4", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", @@ -3693,51 +3325,6 @@ "node": ">=10" } }, - "apps/studio/node_modules/next": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/next/-/next-13.5.6.tgz", - "integrity": "sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==", - "dependencies": { - "@next/env": "13.5.6", - "@swc/helpers": "0.5.2", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.31", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=16.14.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.5.6", - "@next/swc-darwin-x64": "13.5.6", - "@next/swc-linux-arm64-gnu": "13.5.6", - "@next/swc-linux-arm64-musl": "13.5.6", - "@next/swc-linux-x64-gnu": "13.5.6", - "@next/swc-linux-x64-musl": "13.5.6", - "@next/swc-win32-arm64-msvc": "13.5.6", - "@next/swc-win32-ia32-msvc": "13.5.6", - "@next/swc-win32-x64-msvc": "13.5.6" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, "apps/studio/node_modules/openapi-fetch": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.6.2.tgz", @@ -3797,8 +3384,8 @@ "@code-hike/mdx": "^0.9.0", "@heroicons/react": "^1.0.6", "@mdx-js/react": "^2.3.0", - "@next/bundle-analyzer": "^13.5.6", - "@next/mdx": "^13.5.6", + "@next/bundle-analyzer": "^14.1.4", + "@next/mdx": "^14.1.4", "@octokit/auth-app": "^6.0.3", "@octokit/core": "^5.0.2", "@octokit/graphql": "^7.0.2", @@ -3807,7 +3394,8 @@ "@react-three/fiber": "^7.0.29", "@supabase/auth-helpers-react": "^0.4.2", "@supabase/auth-ui-react": "^0.4.5", - "@supabase/supabase-js": "^2.39.3", + "@supabase/supabase-js": "^2.41.1", + "animejs": "^3.2.2", "classnames": "^2.3.1", "cobe": "^0.6.2", "common": "*", @@ -3819,10 +3407,10 @@ "gray-matter": "^4.0.3", "icons": "*", "markdown-toc": "^1.2.0", - "next": "^13.4.8", + "next": "^14.1.4", "next-mdx-remote": "^4.4.1", "next-seo": "^6.5.0", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "parse-numeric-range": "^1.3.0", "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", @@ -3851,6 +3439,7 @@ "yup": "^1.4.0" }, "devDependencies": { + "@types/animejs": "^3.1.12", "@types/classnames": "^2.3.1", "@types/dat.gui": "^0.7.10", "@types/mdx-js__react": "^1.5.6", @@ -3867,154 +3456,6 @@ "tsconfig": "*" } }, - "apps/www/node_modules/@next/env": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.8.tgz", - "integrity": "sha512-twuSf1klb3k9wXI7IZhbZGtFCWvGD4wXTY2rmvzIgVhXhs7ISThrbNyutBx3jWIL8Y/Hk9+woytFz5QsgtcRKQ==" - }, - "apps/www/node_modules/@next/swc-darwin-arm64": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.8.tgz", - "integrity": "sha512-MSFplVM4dTWOuKAUv0XR9gY7AWtMSBu9os9f+kp+s5rWhM1I2CdR3obFttd6366nS/W/VZxbPM5oEIdlIa46zA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-darwin-x64": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.8.tgz", - "integrity": "sha512-Reox+UXgonon9P0WNDE6w85DGtyBqGitl/ryznOvn6TvfxEaZIpTgeu3ZrJLU9dHSMhiK7YAM793mE/Zii2/Qw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.8.tgz", - "integrity": "sha512-kdyzYvAYtqQVgzIKNN7e1rLU8aZv86FDSRqPlOkKZlvqudvTO0iohuTPmnEEDlECeBM6qRPShNffotDcU/R2KA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.8.tgz", - "integrity": "sha512-oWxx4yRkUGcR81XwbI+T0zhZ3bDF6V1aVLpG+C7hSG50ULpV8gC39UxVO22/bv93ZlcfMY4zl8xkz9Klct6dpQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.8.tgz", - "integrity": "sha512-anhtvuO6eE9YRhYnaEGTfbpH3L5gT/9qPFcNoi6xS432r/4DAtpJY8kNktqkTVevVIC/pVumqO8tV59PR3zbNg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.8.tgz", - "integrity": "sha512-aR+J4wWfNgH1DwCCBNjan7Iumx0lLtn+2/rEYuhIrYLY4vnxqSVGz9u3fXcgUwo6Q9LT8NFkaqK1vPprdq+BXg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.8.tgz", - "integrity": "sha512-OWBKIrJwQBTqrat0xhxEB/jcsjJR3+diD9nc/Y8F1mRdQzsn4bPsomgJyuqPVZs6Lz3K18qdIkvywmfSq75SsQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.8.tgz", - "integrity": "sha512-agiPWGjUndXGTOn4ChbKipQXRA6/UPkywAWIkx7BhgGv48TiJfHTK6MGfBoL9tS6B4mtW39++uy0wFPnfD0JWg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.8.tgz", - "integrity": "sha512-UIRKoByVKbuR6SnFG4JM8EMFlJrfEGuUQ1ihxzEleWcNwRMMiVaCj1KyqfTOW8VTQhJ0u8P1Ngg6q1RwnIBTtw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/www/node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "dependencies": { - "tslib": "^2.4.0" - } - }, "apps/www/node_modules/@types/mdx-js__react": { "version": "1.5.6", "dev": true, @@ -4068,79 +3509,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "apps/www/node_modules/next": { - "version": "13.4.8", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.8.tgz", - "integrity": "sha512-lxUjndYKjZHGK3CWeN2RI+/6ni6EUvjiqGWXAYPxUfGIdFGQ5XoisrqAJ/dF74aP27buAfs8MKIbIMMdxjqSBg==", - "dependencies": { - "@next/env": "13.4.8", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0", - "zod": "3.21.4" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=16.8.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.8", - "@next/swc-darwin-x64": "13.4.8", - "@next/swc-linux-arm64-gnu": "13.4.8", - "@next/swc-linux-arm64-musl": "13.4.8", - "@next/swc-linux-x64-gnu": "13.4.8", - "@next/swc-linux-x64-musl": "13.4.8", - "@next/swc-win32-arm64-msvc": "13.4.8", - "@next/swc-win32-ia32-msvc": "13.4.8", - "@next/swc-win32-x64-msvc": "13.4.8" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "fibers": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "apps/www/node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "apps/www/node_modules/slash": { "version": "4.0.0", "license": "MIT", @@ -4151,14 +3519,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "apps/www/node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "license": "MIT", @@ -6970,7 +6330,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -8667,10 +8026,11 @@ } }, "node_modules/@next/bundle-analyzer": { - "version": "13.5.6", - "license": "MIT", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-14.1.4.tgz", + "integrity": "sha512-IpF/18HcAOcfHRr24tqPOUpMmVKIqvkCxIubMeRYWCXs3jm7niPGrt8Mu74yMDzfGlUwgQA6Xd6BUc5+jQxcEg==", "dependencies": { - "webpack-bundle-analyzer": "4.7.0" + "webpack-bundle-analyzer": "4.10.1" } }, "node_modules/@next/env": { @@ -8706,9 +8066,9 @@ } }, "node_modules/@next/mdx": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/mdx/-/mdx-13.5.6.tgz", - "integrity": "sha512-2AMyCrz1SxSWNUpADyLz3RbPbq0GHrchbO7Msvg7IsH8MrTw3VYaZSI1KNa6JzZIoykwtNVSEL+uBmPZi106Jw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/mdx/-/mdx-14.1.4.tgz", + "integrity": "sha512-FyuDXPTEmuIqtj/AxaKLvwiEZb6hDviq6Ywn8ZlsZOlvYSWpcZGuQrYrDulrdIm/I48hHXANor7EiJzTbVig8Q==", "dependencies": { "source-map": "^0.7.0" }, @@ -9018,9 +8378,9 @@ } }, "node_modules/@octokit/core": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.2.tgz", - "integrity": "sha512-cZUy1gUvd4vttMic7C0lwPed8IYXWYp8kHIMatyhY8t8n3Cpw2ILczkV5pGMPqef7v0bLo0pOHrEHarsau2Ydg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz", + "integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==", "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.0.0", @@ -9288,8 +8648,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.23", - "license": "MIT" + "version": "1.0.0-next.25", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", + "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" }, "node_modules/@popperjs/core": { "version": "2.11.8", @@ -11130,6 +10491,202 @@ "version": "2.0.2", "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.1.tgz", + "integrity": "sha512-4C4UERETjXpC4WpBXDbkgNVgHyWfG3B/NKY46e7w5H134UDOFqUJKpsLm0UYmuupW+aJmRgeScrDNfvZ5WV80A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.1.tgz", + "integrity": "sha512-TrTaFJ9pXgfXEiJKQ3yQRelpQFqgRzVR9it8DbeRzG0RX7mKUy0bqhCFsgevwXLJepQKTnLl95TnPGf9T9AMOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.1.tgz", + "integrity": "sha512-fz7jN6ahTI3cKzDO2otQuybts5cyu0feymg0bjvYCBrZQ8tSgE8pc0sSNEuGvifrQJWiwx9F05BowihmLxeQKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.1.tgz", + "integrity": "sha512-WTvdz7SLMlJpektdrnWRUN9C0N2qNHwNbWpNo0a3Tod3gb9leX+yrYdCeB7VV36OtoyiPAivl7/xZ3G1z5h20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.1.tgz", + "integrity": "sha512-dBHQl+7wZzBYcIF6o4k2XkAfwP2ks1mYW2q/Gzv9n39uDcDiAGDqEyml08OdY0BIct0yLSPkDTqn4i6czpBLLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.1.tgz", + "integrity": "sha512-bur4JOxvYxfrAmocRJIW0SADs3QdEYK6TQ7dTNz6Z4/lySeu3Z1H/+tl0a4qDYv0bCdBpUYM0sYa/X+9ZqgfSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.1.tgz", + "integrity": "sha512-ssp77SjcDIUSoUyj7DU7/5iwM4ZEluY+N8umtCT9nBRs3u045t0KkW02LTyHouHDomnMXaXSZcCSr2bdMK63kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.1.tgz", + "integrity": "sha512-Jv1DkIvwEPAb+v25/Unrnnq9BO3F5cbFPT821n3S5litkz+O5NuXuNhqtPx5KtcwOTtaqkTsO+IVzJOsxd11aQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.1.tgz", + "integrity": "sha512-U564BrhEfaNChdATQaEODtquCC7Ez+8Hxz1h5MAdMYj0AqD0GA9rHCpElajb/sQcaFL6NXmHc5O+7FXpWMa73Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.1.tgz", + "integrity": "sha512-zGRDulLTeDemR8DFYyFIQ8kMP02xpUsX4IBikc7lwL9PrwR3gWmX2NopqiGlI2ZVWMl15qZeUjumTwpv18N7sQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.1.tgz", + "integrity": "sha512-VTk/MveyPdMFkYJJPCkYBw07KcTkGU2hLEyqYMsU4NjiOfzoaDTW9PWGRsNwiOA3qI0k/JQPjkl/4FCK1smskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.1.tgz", + "integrity": "sha512-L+hX8Dtibb02r/OYCsp4sQQIi3ldZkFI0EUkMTDwRfFykXBPptoz/tuuGqEd3bThBSLRWPR6wsixDSgOx/U3Zw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.1.tgz", + "integrity": "sha512-+dI2jVPfM5A8zme8riEoNC7UKk0Lzc7jCj/U89cQIrOjrZTCWZl/+IXUeRT2rEZ5j25lnSA9G9H1Ob9azaF/KQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.1.tgz", + "integrity": "sha512-YY1Exxo2viZ/O2dMHuwQvimJ0SqvL+OAWQLLY6rvXavgQKjhQUzn7nc1Dd29gjB5Fqi00nrBWctJBOyfVMIVxw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@rushstack/eslint-patch": { "version": "1.5.1", "license": "MIT" @@ -11138,36 +10695,68 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/@sentry-internal/tracing": { - "version": "7.77.0", - "license": "MIT", + "node_modules/@sentry-internal/feedback": { + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.108.0.tgz", + "integrity": "sha512-8JcgZEnk1uWrXJhsd3iRvFtEiVeaWOEhN0NZwhwQXHfvODqep6JtrkY1yCIyxbpA37aZmrPc2JhyotRERGfUjg==", "dependencies": { - "@sentry/core": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0" + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sentry-internal/replay-canvas": { + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.108.0.tgz", + "integrity": "sha512-R5tvjGqWUV5vSk0N1eBgVW7wIADinrkfDEBZ9FyKP2mXHBobsyNGt30heJDEqYmVqluRqjU2NuIRapsnnrpGnA==", + "dependencies": { + "@sentry/core": "7.108.0", + "@sentry/replay": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sentry-internal/tracing": { + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.108.0.tgz", + "integrity": "sha512-zuK5XsTsb+U+hgn3SPetYDAogrXsM16U/LLoMW7+TlC6UjlHGYQvmX3o+M2vntejoU1QZS8m1bCAZSMWEypAEw==", + "dependencies": { + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.108.0.tgz", + "integrity": "sha512-FNpzsdTvGvdHJMUelqEouUXMZU7jC+dpN7CdT6IoHVVFEkoAgrjMVUhXZoQ/dmCkdKWHmFSQhJ8Fm6V+e9Aq0A==", "dependencies": { - "@sentry-internal/tracing": "7.77.0", - "@sentry/core": "7.77.0", - "@sentry/replay": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0" + "@sentry-internal/feedback": "7.108.0", + "@sentry-internal/replay-canvas": "7.108.0", + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/replay": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/cli": { - "version": "1.75.2", + "version": "1.77.3", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.77.3.tgz", + "integrity": "sha512-c3eDqcDRmy4TFz2bFU5Y6QatlpoBPPa8cxBooaS4aMQpnIdLYPF1xhyyiW0LQlDUNc3rRjNF7oN5qKoaRoMTQQ==", "hasInstallScript": true, - "license": "BSD-3-Clause", "dependencies": { "https-proxy-agent": "^5.0.0", "mkdirp": "^0.5.5", @@ -11185,7 +10774,8 @@ }, "node_modules/@sentry/cli/node_modules/mkdirp": { "version": "0.5.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dependencies": { "minimist": "^1.2.6" }, @@ -11194,23 +10784,25 @@ } }, "node_modules/@sentry/core": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.108.0.tgz", + "integrity": "sha512-I/VNZCFgLASxHZaD0EtxZRM34WG9w2gozqgrKGNMzAymwmQ3K9g/1qmBy4e6iS3YRptb7J5UhQkZQHrcwBbjWQ==", "dependencies": { - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0" + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/integrations": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.108.0.tgz", + "integrity": "sha512-b/WbK1f3x2rQ4aJJSA4VSwpBXrXFm1Nzrca3Y9qW0MI1wjZEYsDDrh9m6ulLdVBl4YDc2VqYp1COwU/NjuHlog==", "dependencies": { - "@sentry/core": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0", "localforage": "^1.8.1" }, "engines": { @@ -11218,18 +10810,19 @@ } }, "node_modules/@sentry/nextjs": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-7.108.0.tgz", + "integrity": "sha512-etBrMSLRbNAzozetBeL6D+lR9lRAyHmV7NUBGCX9lQvgmcdxkQa15EX8pIKjsMejZ8xAZNsqYVIByIs67A77rg==", "dependencies": { "@rollup/plugin-commonjs": "24.0.0", - "@sentry/core": "7.77.0", - "@sentry/integrations": "7.77.0", - "@sentry/node": "7.77.0", - "@sentry/react": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0", - "@sentry/vercel-edge": "7.77.0", - "@sentry/webpack-plugin": "1.20.0", + "@sentry/core": "7.108.0", + "@sentry/integrations": "7.108.0", + "@sentry/node": "7.108.0", + "@sentry/react": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0", + "@sentry/vercel-edge": "7.108.0", + "@sentry/webpack-plugin": "1.21.0", "chalk": "3.0.0", "resolve": "1.22.8", "rollup": "2.78.0", @@ -11291,26 +10884,28 @@ } }, "node_modules/@sentry/node": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.108.0.tgz", + "integrity": "sha512-pMxc9txnDDkU4Z8k2Uw/DPSLPehNtWV3mjJ3+my0AMORGYrXLkJI93tddlE5z/7k+GEJdj1HsOLgxUN0OU+HGA==", "dependencies": { - "@sentry-internal/tracing": "7.77.0", - "@sentry/core": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0", - "https-proxy-agent": "^5.0.0" + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/react": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.108.0.tgz", + "integrity": "sha512-C60arh5/gtO42eMU9l34aWlKDLZUO+1j1goaEf/XRSwUcyJS9tbJrs+mT4nbKxUsEG714It2gRbfSEvh1eXmCg==", "dependencies": { - "@sentry/browser": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0", + "@sentry/browser": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0", "hoist-non-react-statics": "^3.3.2" }, "engines": { @@ -11321,52 +10916,58 @@ } }, "node_modules/@sentry/replay": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.108.0.tgz", + "integrity": "sha512-jo8fDOzcZJclP1+4n9jUtVxTlBFT9hXwxhAMrhrt70FV/nfmCtYQMD3bzIj79nwbhUtFP6pN39JH1o7Xqt1hxQ==", "dependencies": { - "@sentry-internal/tracing": "7.77.0", - "@sentry/core": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0" + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/types": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.108.0.tgz", + "integrity": "sha512-bKtHITmBN3kqtqE5eVvL8mY8znM05vEodENwRpcm6TSrrBjC2RnwNWVwGstYDdHpNfFuKwC8mLY9bgMJcENo8g==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.108.0.tgz", + "integrity": "sha512-a45yEFD5qtgZaIFRAcFkG8C8lnDzn6t4LfLXuV4OafGAy/3ZAN3XN8wDnrruHkiUezSSANGsLg3bXaLW/JLvJw==", "dependencies": { - "@sentry/types": "7.77.0" + "@sentry/types": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/vercel-edge": { - "version": "7.77.0", - "license": "MIT", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-7.108.0.tgz", + "integrity": "sha512-dUuUEswaVIzsJnzTfaJxrvkfOowrlJxxHo2AybPDym2rob7CdaLdDJIYJa83X7QeAKMkTgLny/gYSQYC0E4UyA==", "dependencies": { - "@sentry/core": "7.77.0", - "@sentry/types": "7.77.0", - "@sentry/utils": "7.77.0" + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/webpack-plugin": { - "version": "1.20.0", - "license": "MIT", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-1.21.0.tgz", + "integrity": "sha512-x0PYIMWcsTauqxgl7vWUY6sANl+XGKtx7DCVnnY7aOIIlIna0jChTAPANTfA2QrK+VK+4I/4JxatCEZBnXh3Og==", "dependencies": { - "@sentry/cli": "^1.74.6", + "@sentry/cli": "^1.77.1", "webpack-sources": "^2.0.0 || ^3.0.0" }, "engines": { @@ -16272,6 +15873,14 @@ "@supabase/supabase-js": "^2.19.0" } }, + "node_modules/@supabase/auth-js": { + "version": "2.63.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.63.0.tgz", + "integrity": "sha512-yIgcHnlgv24GxHtVGUhwGqAFDyJkPIC/xjx7HostN08A8yCy8HIfl4JEkTKyBqD1v1L05jNEJOUke4Lf4O1+Qg==", + "dependencies": { + "@supabase/node-fetch": "^2.6.14" + } + }, "node_modules/@supabase/auth-ui-react": { "version": "0.4.5", "dependencies": { @@ -16297,8 +15906,9 @@ "link": true }, "node_modules/@supabase/functions-js": { - "version": "2.1.5", - "license": "MIT", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.2.2.tgz", + "integrity": "sha512-sJGq1nludmi7pY/fdtCpyY/pYonx7MfHdN408bqb736guWcVI1AChYVbI4kUM978EuOE4Ci6l7bUudfGg07QRw==", "dependencies": { "@supabase/node-fetch": "^2.6.14" } @@ -16307,17 +15917,10 @@ "resolved": "apps/docs/spec/parser", "link": true }, - "node_modules/@supabase/gotrue-js": { - "version": "2.62.0", - "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.62.0.tgz", - "integrity": "sha512-4eBuZNXGOk7ewqJuHPYMnk8clCtEx6Hfnu6yHLjZlx7w18TqcojcTRUBZagErtpgwwdfzUwKbquexhbrpH/ysw==", - "dependencies": { - "@supabase/node-fetch": "^2.6.14" - } - }, "node_modules/@supabase/node-fetch": { - "version": "2.6.14", - "license": "MIT", + "version": "2.6.15", + "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", + "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -16341,6 +15944,10 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/@supabase/pg-meta": { + "resolved": "packages/pg-meta", + "link": true + }, "node_modules/@supabase/postgres-meta": { "version": "0.64.6", "dev": true, @@ -16436,23 +16043,24 @@ } }, "node_modules/@supabase/storage-js": { - "version": "2.5.4", - "license": "MIT", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.5.tgz", + "integrity": "sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==", "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/supabase-js": { - "version": "2.39.3", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.39.3.tgz", - "integrity": "sha512-NoltJSaJNKDJNutO5sJPAAi5RIWrn1z2XH+ig1+cHDojT6BTN7TvZPNa3Kq3gFQWfO5H1N9El/bCTZJ3iFW2kQ==", + "version": "2.41.1", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.41.1.tgz", + "integrity": "sha512-xmECLhYugMo/6SObpsOhu5xaxVfsk+JK/d4JSh055bpESmgmN3PLpzbfqejKCpaUeeUNF21+lrJp/U9HQzT9mA==", "dependencies": { - "@supabase/functions-js": "^2.1.5", - "@supabase/gotrue-js": "^2.60.0", - "@supabase/node-fetch": "^2.6.14", - "@supabase/postgrest-js": "^1.9.0", - "@supabase/realtime-js": "^2.9.3", - "@supabase/storage-js": "^2.5.4" + "@supabase/auth-js": "2.63.0", + "@supabase/functions-js": "2.2.2", + "@supabase/node-fetch": "2.6.15", + "@supabase/postgrest-js": "1.9.2", + "@supabase/realtime-js": "2.9.3", + "@supabase/storage-js": "2.5.5" } }, "node_modules/@swc/core": { @@ -16843,6 +16451,12 @@ "@types/estree": "*" } }, + "node_modules/@types/animejs": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@types/animejs/-/animejs-3.1.12.tgz", + "integrity": "sha512-fpdH+ZtlO0kqjTOqRaBdsEmvpRNOayI8k4EVkEtitL5l6wducDOXk0rgQgfZqWf/ZX9DzXrHf257S5i9xTcISQ==", + "dev": true + }, "node_modules/@types/aria-query": { "version": "5.0.2", "dev": true, @@ -17209,8 +16823,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.2", - "license": "MIT" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/estree-jsx": { "version": "1.0.1", @@ -17484,6 +17099,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/pg-format": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/pg-format/-/pg-format-1.0.5.tgz", + "integrity": "sha512-i+oEEJEC+1I3XAhgqtVp45Faj8MBbV0Aoq4rHsHD7avgLjyDkaWKObd514g0Q/DOUkdxU0P4CQ0iq2KR4SoJcw==", + "dev": true + }, "node_modules/@types/phoenix": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.4.tgz", @@ -17988,6 +17609,121 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/@vitest/runner": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz", + "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@vitest/utils": "1.4.0", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz", + "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vitest/snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/snapshot/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/@vitest/spy": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", @@ -18457,8 +18193,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "license": "MIT", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "engines": { "node": ">=0.4.0" } @@ -18639,6 +18376,11 @@ "properties": "^1.2.1" } }, + "node_modules/animejs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.2.tgz", + "integrity": "sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ==" + }, "node_modules/ansi-colors": { "version": "4.1.3", "dev": true, @@ -19784,12 +19526,13 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.1", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -19797,7 +19540,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -19808,24 +19551,27 @@ }, "node_modules/body-parser/node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -19835,13 +19581,15 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/body-parser/node_modules/qs": { "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -20216,6 +19964,17 @@ "node": ">=10" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/cacache": { "version": "15.3.0", "license": "ISC", @@ -21367,8 +21126,9 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -23039,7 +22799,8 @@ }, "node_modules/duplexer": { "version": "0.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "node_modules/duplexify": { "version": "3.7.1", @@ -24616,16 +24377,17 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.18.2", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -24656,6 +24418,15 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "dev": true, @@ -25955,7 +25726,8 @@ }, "node_modules/gzip-size": { "version": "6.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", "dependencies": { "duplexer": "^0.1.2" }, @@ -26948,7 +26720,6 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "dev": true, "license": "MIT" }, "node_modules/html-minifier-terser": { @@ -27191,7 +26962,8 @@ }, "node_modules/immediate": { "version": "3.0.6", - "license": "MIT" + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immutability-helper": { "version": "3.1.1", @@ -27364,6 +27136,15 @@ "fast-loops": "^1.1.3" } }, + "node_modules/input-otp": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.2.3.tgz", + "integrity": "sha512-pxYvgnihL9KAdpcShX2+iKctdMRbDs36bIqd8uIsN3e5vv9VjMv2bhO3S5Bl1PjcDPsA/OXZe5R71n8oVtucfQ==", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/internal-slot": { "version": "1.0.5", "license": "MIT", @@ -27777,7 +27558,6 @@ }, "node_modules/is-plain-object": { "version": "5.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -30340,7 +30120,8 @@ }, "node_modules/lie": { "version": "3.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", "dependencies": { "immediate": "~3.0.5" } @@ -30439,9 +30220,28 @@ "json5": "lib/cli.js" } }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/localforage": { "version": "1.10.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", "dependencies": { "lie": "3.1.1" } @@ -32714,8 +32514,9 @@ }, "node_modules/media-typer": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -35056,6 +34857,20 @@ "version": "0.5.3", "license": "MIT" }, + "node_modules/mlly": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, "node_modules/mobx": { "version": "6.11.0", "license": "MIT", @@ -35158,8 +34973,9 @@ } }, "node_modules/mrmime": { - "version": "1.0.1", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "engines": { "node": ">=10" } @@ -35337,18 +35153,18 @@ } }, "node_modules/next-themes": { - "version": "0.2.1", - "license": "MIT", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", "peerDependencies": { - "next": "*", - "react": "*", - "react-dom": "*" + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" } }, "node_modules/nextjs-node-loader": { - "version": "1.1.5-alpha.0", - "resolved": "https://registry.npmjs.org/nextjs-node-loader/-/nextjs-node-loader-1.1.5-alpha.0.tgz", - "integrity": "sha512-EaY047JUWPlD2pOwRdcYPeyJrUTOfNOGcLyPaiped1bFHvHGIAN8596IbFAM4vwaOMpICodC1mEoOXTKvtcrCA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/nextjs-node-loader/-/nextjs-node-loader-1.1.5.tgz", + "integrity": "sha512-tS2wWPh8QsQHBVNG8w7xzL3ua+OFnmFvcOFxrAQsfK4T017nOiCUrybVWVieilEn1z8CqODcRw1z70mFRPQi1Q==", "dev": true, "dependencies": { "loader-utils": "^2.0.3" @@ -36677,7 +36493,8 @@ }, "node_modules/opener": { "version": "1.5.2", - "license": "(WTFPL OR MIT)", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "bin": { "opener": "bin/opener-bin.js" } @@ -37142,7 +36959,6 @@ }, "node_modules/pg-format": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "node": ">=4.0" @@ -37305,6 +37121,19 @@ "node": ">=10" } }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, "node_modules/playwright": { "version": "1.41.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", @@ -38389,9 +38218,10 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -38404,16 +38234,18 @@ }, "node_modules/raw-body/node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -41776,6 +41608,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/signal-exit": { "version": "4.1.0", "license": "ISC", @@ -41934,12 +41774,13 @@ } }, "node_modules/sirv": { - "version": "1.0.19", - "license": "MIT", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^1.0.0" + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" }, "engines": { "node": ">= 10" @@ -42037,8 +41878,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "license": "BSD-3-Clause", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -42218,6 +42060,14 @@ "node": ">=8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/stackframe": { "version": "1.3.4", "license": "MIT" @@ -42275,6 +42125,14 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/stdin-blocker": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/stdin-blocker/-/stdin-blocker-2.0.0.tgz", @@ -42696,6 +42554,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "js-tokens": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", @@ -44022,11 +43902,30 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/tinycolor2": { "version": "1.6.0", "dev": true, "license": "MIT" }, + "node_modules/tinypool": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.3.tgz", + "integrity": "sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tinyspy": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", @@ -44130,8 +44029,9 @@ "license": "MIT" }, "node_modules/totalist": { - "version": "1.1.0", - "license": "MIT", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "engines": { "node": ">=6" } @@ -44573,26 +44473,26 @@ } }, "node_modules/turbo": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.13.0.tgz", - "integrity": "sha512-r02GtNmkOPcQvUzVE6lg474QVLyU02r3yh3lUGqrFHf5h5ZEjgDGWILsAUqplVqjri1Y/oOkTssks4CObTAaiw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.13.2.tgz", + "integrity": "sha512-rX/d9f4MgRT3yK6cERPAkfavIxbpBZowDQpgvkYwGMGDQ0Nvw1nc0NVjruE76GrzXQqoxR1UpnmEP54vBARFHQ==", "dev": true, "bin": { "turbo": "bin/turbo" }, "optionalDependencies": { - "turbo-darwin-64": "1.13.0", - "turbo-darwin-arm64": "1.13.0", - "turbo-linux-64": "1.13.0", - "turbo-linux-arm64": "1.13.0", - "turbo-windows-64": "1.13.0", - "turbo-windows-arm64": "1.13.0" + "turbo-darwin-64": "1.13.2", + "turbo-darwin-arm64": "1.13.2", + "turbo-linux-64": "1.13.2", + "turbo-linux-arm64": "1.13.2", + "turbo-windows-64": "1.13.2", + "turbo-windows-arm64": "1.13.2" } }, "node_modules/turbo-darwin-64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.13.0.tgz", - "integrity": "sha512-ctHeJXtQgBcgxnCXwrJTGiq57HtwF7zWz5NTuSv//5yeU01BtQIt62ArKfjudOhRefWJbX3Z5srn88XTb9hfww==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.13.2.tgz", + "integrity": "sha512-CCSuD8CfmtncpohCuIgq7eAzUas0IwSbHfI8/Q3vKObTdXyN8vAo01gwqXjDGpzG9bTEVedD0GmLbD23dR0MLA==", "cpu": [ "x64" ], @@ -44603,9 +44503,9 @@ ] }, "node_modules/turbo-darwin-arm64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.13.0.tgz", - "integrity": "sha512-/Q9/pNFkF9w83tNxwMpgapwLYdQ12p8mpty2YQRoUiS9ClWkcqe136jR0mtuMqzlNlpREOFZaoyIthjt6Sdo0g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.13.2.tgz", + "integrity": "sha512-0HySm06/D2N91rJJ89FbiI/AodmY8B3WDSFTVEpu2+8spUw7hOJ8okWOT0e5iGlyayUP9gr31eOeL3VFZkpfCw==", "cpu": [ "arm64" ], @@ -44616,9 +44516,9 @@ ] }, "node_modules/turbo-linux-64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.13.0.tgz", - "integrity": "sha512-hgbT7o020BGV4L7Sd8hhFTd5zVKPKxbsr0dPfel/9NkdTmptz2aGZ0Vb2MAa18SY3XaCQpDxmdYuOzvvRpo5ZA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.13.2.tgz", + "integrity": "sha512-7HnibgbqZrjn4lcfIouzlPu8ZHSBtURG4c7Bedu7WJUDeZo+RE1crlrQm8wuwO54S0siYqUqo7GNHxu4IXbioQ==", "cpu": [ "x64" ], @@ -44629,9 +44529,9 @@ ] }, "node_modules/turbo-linux-arm64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.13.0.tgz", - "integrity": "sha512-WK01i2wDZARrV+HEs495A3hNeGMwQR5suYk7G+ceqqW7b+dOTlQdvUjnI3sg7wAnZPgjafFs/hoBaZdJjVa/nw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.13.2.tgz", + "integrity": "sha512-sUq4dbpk6SNKg/Hkwn256Vj2AEYSQdG96repio894h5/LEfauIK2QYiC/xxAeW3WBMc6BngmvNyURIg7ltrePg==", "cpu": [ "arm64" ], @@ -44642,9 +44542,9 @@ ] }, "node_modules/turbo-windows-64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.13.0.tgz", - "integrity": "sha512-hJgSZJZwlWHNwLEthaqJqJWGm4NqF5X/I7vE0sPE4i/jeDl8f0n1hcOkgJkJiNXVxhj+qy/9+4dzbPLKT9imaQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.13.2.tgz", + "integrity": "sha512-DqzhcrciWq3dpzllJR2VVIyOhSlXYCo4mNEWl98DJ3FZ08PEzcI3ceudlH6F0t/nIcfSItK1bDP39cs7YoZHEA==", "cpu": [ "x64" ], @@ -44655,9 +44555,9 @@ ] }, "node_modules/turbo-windows-arm64": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.13.0.tgz", - "integrity": "sha512-L/ErxYoXeq8tmjU/AIGicC9VyBN1zdYw8JlM4yPmMI0pJdY8E4GaYK1IiIazqq7M72lmQhU/WW7fV9FqEktwrw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.13.2.tgz", + "integrity": "sha512-WnPMrwfCXxK69CdDfS1/j2DlzcKxSmycgDAqV0XCYpK/812KB0KlvsVAt5PjEbZGXkY88pCJ1BLZHAjF5FcbqA==", "cpu": [ "arm64" ], @@ -44697,8 +44597,9 @@ }, "node_modules/type-is": { "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -44842,9 +44743,9 @@ } }, "node_modules/undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -45741,6 +45642,854 @@ "@types/d3-path": "*" } }, + "node_modules/vite": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.36", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz", + "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/vite/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "optional": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "optional": true, + "peer": true, + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.1.tgz", + "integrity": "sha512-hFi+fU132IvJ2ZuihN56dwgpltpmLZHZWsx27rMCTZ2sYwrqlgL5sECGy1eeV2lAihD8EzChBVVhsXci0wD4Tg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.1", + "@rollup/rollup-android-arm64": "4.13.1", + "@rollup/rollup-darwin-arm64": "4.13.1", + "@rollup/rollup-darwin-x64": "4.13.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.1", + "@rollup/rollup-linux-arm64-gnu": "4.13.1", + "@rollup/rollup-linux-arm64-musl": "4.13.1", + "@rollup/rollup-linux-riscv64-gnu": "4.13.1", + "@rollup/rollup-linux-s390x-gnu": "4.13.1", + "@rollup/rollup-linux-x64-gnu": "4.13.1", + "@rollup/rollup-linux-x64-musl": "4.13.1", + "@rollup/rollup-win32-arm64-msvc": "4.13.1", + "@rollup/rollup-win32-ia32-msvc": "4.13.1", + "@rollup/rollup-win32-x64-msvc": "4.13.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/vitest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz", + "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@vitest/expect": "1.4.0", + "@vitest/runner": "1.4.0", + "@vitest/snapshot": "1.4.0", + "@vitest/spy": "1.4.0", + "@vitest/utils": "1.4.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.2", + "vite": "^5.0.0", + "vite-node": "1.4.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.4.0", + "@vitest/ui": "1.4.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@vitest/expect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz", + "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@vitest/spy": "1.4.0", + "@vitest/utils": "1.4.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/spy": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz", + "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/vitest/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/vitest/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -45896,17 +46645,22 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.7.0", - "license": "MIT", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "dependencies": { + "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", - "lodash": "^4.17.20", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", "opener": "^1.5.2", - "sirv": "^1.0.7", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { @@ -45916,53 +46670,21 @@ "node": ">= 10.13.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { - "version": "4.3.0", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/chalk": { - "version": "4.1.2", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/has-flag": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { - "version": "7.2.0", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { "version": "7.5.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -45980,9 +46702,10 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "6.1.1", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.12", @@ -46223,6 +46946,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "license": "ISC", @@ -46723,7 +47464,7 @@ "config": "*", "dat.gui": "^0.7.9", "lodash": "^4.17.21", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "react-hot-toast": "^2.4.1", "react-use": "^17.4.0" }, @@ -46734,7 +47475,7 @@ "typescript": "^5.4.3" }, "peerDependencies": { - "@supabase/gotrue-js": "^2.58.0", + "@supabase/auth-js": "^2.63.0", "@supabase/supabase-js": "*", "next": "*", "react": "*", @@ -46916,6 +47657,19 @@ "typescript": "^5.4.3" } }, + "packages/pg-meta": { + "name": "@supabase/pg-meta", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "pg-format": "^1.0.4", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/pg-format": "^1.0.1", + "typescript": "^5.4.3" + } + }, "packages/shared-data": { "version": "0.0.0", "license": "MIT" @@ -46967,9 +47721,10 @@ "common-tags": "^1.8.2", "date-fns": "^2.30.0", "formik": "^2.2.9", + "input-otp": "^1.2.3", "lodash": "^4.17.21", "lucide-react": "^0.338.0", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "openai": "^4.17.0", "postcss": "^8.4.31", "prop-types": "^15.7.2", @@ -47555,7 +48310,7 @@ "license": "MIT", "devDependencies": { "@faker-js/faker": "^6.1.2", - "@supabase/supabase-js": "^2.39.3", + "@supabase/supabase-js": "^2.41.1", "@testdeck/jest": "^0.3.3", "@types/jest": "^29.5.4", "@types/node": "^20.11.16", diff --git a/package.json b/package.json index feef284cb7a..985e260070f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dev:database-design": "turbo run dev --filter=database-design --parallel", "lint": "turbo run lint", "typecheck": "turbo --continue typecheck", - "format": "prettier --write \"apps/**/*.{js,jsx,ts,tsx,css,md,mdx,json}\"", + "format": "prettier --write \"apps/**/*.{js,jsx,ts,tsx,css,md,mdx,json}\" \"packages/pg-meta/**/*.ts\"", "docker:dev": "cd docker && docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up --renew-anon-volumes", "docker:up": "cd docker && docker compose up", "docker:down": "cd docker && docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down --remove-orphans", @@ -37,7 +37,7 @@ "prettier-plugin-sql-cst": "^0.11.0", "sass": "^1.72.0", "supabase": "^1.151.1", - "turbo": "^1.13.0" + "turbo": "^1.13.2" }, "repository": { "type": "git", diff --git a/packages/common/MetaFavicons/pages-router.tsx b/packages/common/MetaFavicons/pages-router.tsx index 27bbf65dbe1..a2e5f157fa5 100644 --- a/packages/common/MetaFavicons/pages-router.tsx +++ b/packages/common/MetaFavicons/pages-router.tsx @@ -31,29 +31,34 @@ const MetaFaviconsPagesRouter = ({ {/* prettier-ignore */} {/* prettier-ignore */} - + {/* prettier-ignore */} {/* prettier-ignore */} - + {/* prettier-ignore */} - + {/* prettier-ignore */} {/* prettier-ignore */} - + {/* prettier-ignore */} {/* prettier-ignore */} - - {/* prettier-ignore */} - - {/* prettier-ignore */} - + {/* prettier-ignore */} {/* prettier-ignore */} - + + {/* prettier-ignore */} + + {/* prettier-ignore */} + + {/* prettier-ignore */} + + {/* prettier-ignore */} + + {/* prettier-ignore */} {/* prettier-ignore */} @@ -69,7 +74,7 @@ const MetaFaviconsPagesRouter = ({ - + {includeRssXmlFeed && ( diff --git a/packages/common/database-types.ts b/packages/common/database-types.ts new file mode 100644 index 00000000000..49a489ef1bd --- /dev/null +++ b/packages/common/database-types.ts @@ -0,0 +1,549 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + +export type Database = { + graphql_public: { + Tables: { + [_ in never]: never + } + Views: { + [_ in never]: never + } + Functions: { + graphql: { + Args: { + operationName?: string + query?: string + variables?: Json + extensions?: Json + } + Returns: Json + } + } + Enums: { + [_ in never]: never + } + CompositeTypes: { + [_ in never]: never + } + } + public: { + Tables: { + feedback: { + Row: { + date_created: string + id: number + metadata: Json | null + page: string + vote: Database["public"]["Enums"]["feedback_vote"] + } + Insert: { + date_created?: string + id?: never + metadata?: Json | null + page: string + vote: Database["public"]["Enums"]["feedback_vote"] + } + Update: { + date_created?: string + id?: never + metadata?: Json | null + page?: string + vote?: Database["public"]["Enums"]["feedback_vote"] + } + Relationships: [] + } + page: { + Row: { + checksum: string | null + content: string | null + fts_tokens: unknown | null + id: number + last_refresh: string | null + meta: Json | null + path: string + source: string | null + title_tokens: unknown | null + type: string | null + version: string | null + } + Insert: { + checksum?: string | null + content?: string | null + fts_tokens?: unknown | null + id?: number + last_refresh?: string | null + meta?: Json | null + path: string + source?: string | null + title_tokens?: unknown | null + type?: string | null + version?: string | null + } + Update: { + checksum?: string | null + content?: string | null + fts_tokens?: unknown | null + id?: number + last_refresh?: string | null + meta?: Json | null + path?: string + source?: string | null + title_tokens?: unknown | null + type?: string | null + version?: string | null + } + Relationships: [] + } + page_section: { + Row: { + content: string | null + embedding: string | null + heading: string | null + id: number + page_id: number + rag_ignore: boolean | null + slug: string | null + token_count: number | null + } + Insert: { + content?: string | null + embedding?: string | null + heading?: string | null + id?: number + page_id: number + rag_ignore?: boolean | null + slug?: string | null + token_count?: number | null + } + Update: { + content?: string | null + embedding?: string | null + heading?: string | null + id?: number + page_id?: number + rag_ignore?: boolean | null + slug?: string | null + token_count?: number | null + } + Relationships: [ + { + foreignKeyName: "page_section_page_id_fkey" + columns: ["page_id"] + isOneToOne: false + referencedRelation: "page" + referencedColumns: ["id"] + }, + ] + } + } + Views: { + [_ in never]: never + } + Functions: { + docs_search_embeddings: { + Args: { + embedding: string + match_threshold: number + } + Returns: { + id: number + path: string + type: string + title: string + subtitle: string + description: string + headings: string[] + slugs: string[] + }[] + } + docs_search_fts: { + Args: { + query: string + } + Returns: { + id: number + path: string + type: string + title: string + subtitle: string + description: string + }[] + } + get_page_parents: { + Args: { + page_id: number + } + Returns: { + id: number + parent_page_id: number + path: string + meta: Json + }[] + } + hnswhandler: { + Args: { + "": unknown + } + Returns: unknown + } + ipv6_active_status: { + Args: { + project_ref: string + } + Returns: { + pgbouncer_active: boolean + vercel_active: boolean + }[] + } + ivfflathandler: { + Args: { + "": unknown + } + Returns: unknown + } + match_page_sections: { + Args: { + embedding: string + match_threshold: number + match_count: number + min_content_length: number + } + Returns: { + id: number + page_id: number + slug: string + heading: string + content: string + similarity: number + }[] + } + match_page_sections_v2: { + Args: { + embedding: string + match_threshold: number + min_content_length: number + } + Returns: { + content: string | null + embedding: string | null + heading: string | null + id: number + page_id: number + rag_ignore: boolean | null + slug: string | null + token_count: number | null + }[] + } + vector_avg: { + Args: { + "": number[] + } + Returns: string + } + vector_dims: { + Args: { + "": string + } + Returns: number + } + vector_norm: { + Args: { + "": string + } + Returns: number + } + vector_out: { + Args: { + "": string + } + Returns: unknown + } + vector_send: { + Args: { + "": string + } + Returns: string + } + vector_typmod_in: { + Args: { + "": unknown[] + } + Returns: number + } + } + Enums: { + feedback_vote: "yes" | "no" + } + CompositeTypes: { + [_ in never]: never + } + } + storage: { + Tables: { + buckets: { + Row: { + allowed_mime_types: string[] | null + avif_autodetection: boolean | null + created_at: string | null + file_size_limit: number | null + id: string + name: string + owner: string | null + owner_id: string | null + public: boolean | null + updated_at: string | null + } + Insert: { + allowed_mime_types?: string[] | null + avif_autodetection?: boolean | null + created_at?: string | null + file_size_limit?: number | null + id: string + name: string + owner?: string | null + owner_id?: string | null + public?: boolean | null + updated_at?: string | null + } + Update: { + allowed_mime_types?: string[] | null + avif_autodetection?: boolean | null + created_at?: string | null + file_size_limit?: number | null + id?: string + name?: string + owner?: string | null + owner_id?: string | null + public?: boolean | null + updated_at?: string | null + } + Relationships: [] + } + migrations: { + Row: { + executed_at: string | null + hash: string + id: number + name: string + } + Insert: { + executed_at?: string | null + hash: string + id: number + name: string + } + Update: { + executed_at?: string | null + hash?: string + id?: number + name?: string + } + Relationships: [] + } + objects: { + Row: { + bucket_id: string | null + created_at: string | null + id: string + last_accessed_at: string | null + metadata: Json | null + name: string | null + owner: string | null + owner_id: string | null + path_tokens: string[] | null + updated_at: string | null + version: string | null + } + Insert: { + bucket_id?: string | null + created_at?: string | null + id?: string + last_accessed_at?: string | null + metadata?: Json | null + name?: string | null + owner?: string | null + owner_id?: string | null + path_tokens?: string[] | null + updated_at?: string | null + version?: string | null + } + Update: { + bucket_id?: string | null + created_at?: string | null + id?: string + last_accessed_at?: string | null + metadata?: Json | null + name?: string | null + owner?: string | null + owner_id?: string | null + path_tokens?: string[] | null + updated_at?: string | null + version?: string | null + } + Relationships: [ + { + foreignKeyName: "objects_bucketId_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets" + referencedColumns: ["id"] + }, + ] + } + } + Views: { + [_ in never]: never + } + Functions: { + can_insert_object: { + Args: { + bucketid: string + name: string + owner: string + metadata: Json + } + Returns: undefined + } + extension: { + Args: { + name: string + } + Returns: string + } + filename: { + Args: { + name: string + } + Returns: string + } + foldername: { + Args: { + name: string + } + Returns: string[] + } + get_size_by_bucket: { + Args: Record + Returns: { + size: number + bucket_id: string + }[] + } + search: { + Args: { + prefix: string + bucketname: string + limits?: number + levels?: number + offsets?: number + search?: string + sortcolumn?: string + sortorder?: string + } + Returns: { + name: string + id: string + updated_at: string + created_at: string + last_accessed_at: string + metadata: Json + }[] + } + } + Enums: { + [_ in never]: never + } + CompositeTypes: { + [_ in never]: never + } + } +} + +type PublicSchema = Database[Extract] + +export type Tables< + PublicTableNameOrOptions extends + | keyof (PublicSchema["Tables"] & PublicSchema["Views"]) + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & + PublicSchema["Views"]) + ? (PublicSchema["Tables"] & + PublicSchema["Views"])[PublicTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + PublicTableNameOrOptions extends + | keyof PublicSchema["Tables"] + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + PublicTableNameOrOptions extends + | keyof PublicSchema["Tables"] + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + PublicEnumNameOrOptions extends + | keyof PublicSchema["Enums"] + | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] + ? PublicSchema["Enums"][PublicEnumNameOrOptions] + : never + diff --git a/packages/common/gotrue.ts b/packages/common/gotrue.ts index e449a70ea4b..e7aca65bf29 100644 --- a/packages/common/gotrue.ts +++ b/packages/common/gotrue.ts @@ -1,4 +1,4 @@ -import { GoTrueClient, navigatorLock } from '@supabase/gotrue-js' +import { AuthClient, navigatorLock } from '@supabase/auth-js' export const STORAGE_KEY = process.env.NEXT_PUBLIC_STORAGE_KEY || 'supabase.dashboard.auth.token' export const AUTH_DEBUG_KEY = @@ -100,7 +100,7 @@ const logIndexedDB = (message: string, ...args: any[]) => { })() } -export const gotrueClient = new GoTrueClient({ +export const gotrueClient = new AuthClient({ url: process.env.NEXT_PUBLIC_GOTRUE_URL, storageKey: STORAGE_KEY, detectSessionInUrl: true, diff --git a/packages/common/hooks/useBreakpoint.tsx b/packages/common/hooks/useBreakpoint.tsx index 6704d7917f9..ca6221326e1 100644 --- a/packages/common/hooks/useBreakpoint.tsx +++ b/packages/common/hooks/useBreakpoint.tsx @@ -1,14 +1,32 @@ -import { useEffect, useState } from 'react' -import { useWindowSize } from 'react-use' -import { isBrowser } from '../helpers' +import { useState } from 'react' +import { useIsomorphicLayoutEffect, useWindowSize } from 'react-use' -export function useBreakpoint(breakpoint = 768) { - if (!isBrowser) return +/** + * Map of Tailwind default breakpoint values. Allows setting a value by + * Tailwind breakpoint, so that it syncs up with CSS changes. + * + * Note Tailwind uses `min-width` logic, whereas we use `max-width` logic, so + * the values are offset by 1px. + * + * Source: + * https://tailwindcss.com/docs/responsive-design + */ +const twBreakpointMap = { + sm: 639, + md: 767, + lg: 1023, + xl: 1027, + '2xl': 1535, +} + +export function useBreakpoint(breakpoint: number | keyof typeof twBreakpointMap = 'lg') { const [isBreakpoint, setIsBreakpoint] = useState(false) const { width } = useWindowSize() - useEffect(() => { - if (width <= breakpoint) { + const _breakpoint = typeof breakpoint === 'string' ? twBreakpointMap[breakpoint] : breakpoint + + useIsomorphicLayoutEffect(() => { + if (width <= _breakpoint) { setIsBreakpoint(true) } else { setIsBreakpoint(false) diff --git a/packages/common/index.tsx b/packages/common/index.tsx index 7b3b81dd207..e86ffed6d47 100644 --- a/packages/common/index.tsx +++ b/packages/common/index.tsx @@ -1,8 +1,9 @@ -export * from './Providers' +export * from './auth' export * from './constants' +export * from './database-types' +export * from './gotrue' export * from './helpers' export * from './hooks' -export * from './gotrue' -export * from './auth' -export * from './telemetry' export * from './MetaFavicons/pages-router' +export * from './Providers' +export * from './telemetry' diff --git a/packages/common/package.json b/packages/common/package.json index 2c8ff686c4c..3765018aff6 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -12,7 +12,7 @@ "config": "*", "dat.gui": "^0.7.9", "lodash": "^4.17.21", - "next-themes": "^0.2.1", + "next-themes": "^0.3.0", "react-hot-toast": "^2.4.1", "react-use": "^17.4.0" }, @@ -24,7 +24,7 @@ }, "peerDependencies": { "@supabase/supabase-js": "*", - "@supabase/gotrue-js": "^2.58.0", + "@supabase/auth-js": "^2.63.0", "next": "*", "react": "*", "react-dom": "*" diff --git a/packages/pg-meta/package.json b/packages/pg-meta/package.json new file mode 100644 index 00000000000..a5ddc5e690b --- /dev/null +++ b/packages/pg-meta/package.json @@ -0,0 +1,16 @@ +{ + "name": "@supabase/pg-meta", + "version": "0.0.0", + "license": "MIT", + "author": "Supabase", + "main": "./src/index.ts", + "repository": "supabase/supabase", + "dependencies": { + "pg-format": "^1.0.4", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/pg-format": "^1.0.1", + "typescript": "^5.4.3" + } +} diff --git a/packages/pg-meta/src/constants.ts b/packages/pg-meta/src/constants.ts new file mode 100644 index 00000000000..c28ea770cc0 --- /dev/null +++ b/packages/pg-meta/src/constants.ts @@ -0,0 +1 @@ +export const DEFAULT_SYSTEM_SCHEMAS = ['information_schema', 'pg_catalog', 'pg_toast'] diff --git a/packages/pg-meta/src/index.ts b/packages/pg-meta/src/index.ts new file mode 100644 index 00000000000..f1262d58ceb --- /dev/null +++ b/packages/pg-meta/src/index.ts @@ -0,0 +1,5 @@ +import schemas from './pg-meta-schemas' + +export default { + schemas, +} diff --git a/packages/pg-meta/src/pg-meta-schemas.ts b/packages/pg-meta/src/pg-meta-schemas.ts new file mode 100644 index 00000000000..8458eeedfe0 --- /dev/null +++ b/packages/pg-meta/src/pg-meta-schemas.ts @@ -0,0 +1,155 @@ +import { ident, literal } from 'pg-format' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants' +import { SCHEMAS_SQL } from './sql/schemas' +import { z } from 'zod' + +const pgSchemaZod = z.object({ + id: z.number(), + name: z.string(), + owner: z.string(), +}) +const pgSchemaArrayZod = z.array(pgSchemaZod) +const pgSchemaOptionalZod = z.optional(pgSchemaZod) + +function list({ + includeSystemSchemas = false, + limit, + offset, +}: { + includeSystemSchemas?: boolean + limit?: number + offset?: number +} = {}): { + sql: string + zod: typeof pgSchemaArrayZod +} { + let sql = SCHEMAS_SQL + if (!includeSystemSchemas) { + sql = `${sql} and not (n.nspname in (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + } + if (limit) { + sql = `${sql} limit ${limit}` + } + if (offset) { + sql = `${sql} offset ${offset}` + } + return { + sql, + zod: pgSchemaArrayZod, + } +} + +function retrieve({ id }: { id: number }): { sql: string; zod: typeof pgSchemaOptionalZod } +function retrieve({ name }: { name: string }): { sql: string; zod: typeof pgSchemaOptionalZod } +function retrieve({ id, name }: { id?: number; name?: string }) { + if (id) { + const sql = `${SCHEMAS_SQL} and n.oid = ${literal(id)};` + return { + sql, + zod: pgSchemaOptionalZod, + } + } else { + const sql = `${SCHEMAS_SQL} and n.nspname = ${literal(name)};` + return { + sql, + zod: pgSchemaOptionalZod, + } + } +} + +type SchemaCreateParams = { + name: string + owner?: string +} +function create({ name, owner }: SchemaCreateParams): { sql: string } { + const sql = `create schema ${ident(name)} + ${owner === undefined ? '' : `authorization ${ident(owner)}`}; +` + return { sql } +} + +type SchemaUpdateParams = { + name?: string + owner?: string +} +function update({ id }: { id: number }, params: SchemaUpdateParams): { sql: string } +function update({ name }: { name: string }, params: SchemaUpdateParams): { sql: string } +function update( + { + id, + name, + }: { + id?: number + name?: string + }, + { name: newName, owner }: SchemaUpdateParams +): { sql: string } { + const sql = ` +do $$ +declare + id oid := ${id === undefined ? `${literal(name)}::regnamespace` : literal(id)}; + old record; + new_name text := ${newName === undefined ? null : literal(newName)}; + new_owner text := ${owner === undefined ? null : literal(owner)}; +begin + select * into old from pg_namespace where oid = id; + if old is null then + raise exception 'Cannot find schema with id %', id; + end if; + + if new_owner is not null then + execute(format('alter schema %I owner to %I;', old.nspname, new_owner)); + end if; + + -- Using the same name in the rename clause gives an error, so only do it if the new name is different. + if new_name is not null and new_name != old.nspname then + execute(format('alter schema %I rename to %I;', old.nspname, new_name)); + end if; +end +$$; +` + return { sql } +} + +type SchemaRemoveParams = { + cascade?: boolean +} +function remove({ id }: { id: number }, params: SchemaRemoveParams): { sql: string } +function remove({ name }: { name: string }, params: SchemaRemoveParams): { sql: string } +function remove( + { + id, + name, + }: { + id?: number + name?: string + }, + { cascade = false }: SchemaRemoveParams = {} +): { sql: string } { + const sql = ` +do $$ +declare + id oid := ${id === undefined ? `${literal(name)}::regnamespace` : literal(id)}; + old record; + cascade bool := ${literal(cascade)}; +begin + select * into old from pg_namespace where oid = id; + if old is null then + raise exception 'Cannot find schema with id %', id; + end if; + + execute(format('drop schema %I %s;', old.nspname, case when cascade then 'cascade' else 'restrict' end)); +end +$$; +` + return { sql } +} + +export default { + list, + retrieve, + create, + update, + remove, + zod: pgSchemaZod, +} diff --git a/packages/pg-meta/src/sql/schemas.ts b/packages/pg-meta/src/sql/schemas.ts new file mode 100644 index 00000000000..1f70f7830f8 --- /dev/null +++ b/packages/pg-meta/src/sql/schemas.ts @@ -0,0 +1,19 @@ +export const SCHEMAS_SQL = ` +-- Adapted from information_schema.schemata + +select + n.oid::int8 as id, + n.nspname as name, + u.rolname as owner +from + pg_namespace n, + pg_roles u +where + n.nspowner = u.oid + and ( + pg_has_role(n.nspowner, 'USAGE') + or has_schema_privilege(n.oid, 'CREATE, USAGE') + ) + and not pg_catalog.starts_with(n.nspname, 'pg_temp_') + and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_') +` diff --git a/packages/pg-meta/tsconfig.json b/packages/pg-meta/tsconfig.json new file mode 100644 index 00000000000..97945ba9796 --- /dev/null +++ b/packages/pg-meta/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "tsconfig/base.json", + "compilerOptions": { + "module": "ESNext" + }, + "include": ["."], + "exclude": ["dist", "build", "node_modules"] +} diff --git a/packages/shared-data/pricing.ts b/packages/shared-data/pricing.ts index df20e5a6875..365c9cd0c88 100644 --- a/packages/shared-data/pricing.ts +++ b/packages/shared-data/pricing.ts @@ -112,7 +112,7 @@ export const pricing: Pricing = { { title: 'Bandwidth', tooltips: { - main: 'Billing is based on the total sum of all outgoing traffic (includes Database, Storage, Realtime, Auth, API, Edge Functions) in GB throughout your billing period.', + main: 'Billing is based on the total sum of all outgoing traffic (includes Database, Storage, Realtime, Auth, API, Edge Functions, Supavisor) in GB throughout your billing period.', }, plans: { free: '5 GB included', @@ -293,6 +293,19 @@ export const pricing: Pricing = { }, usage_based: false, }, + { + title: 'Content Delivery Network', + tooltips: { + main: 'Assets in Storage are automatically cached on a CDN. With Smart CDN caching enabled, the CDN cache is automatically re-validated when the underlying asset changes. CDN caching is enabled across all plans and assets in the paid plans are cached via the Smart CDN.', + }, + plans: { + free: 'Basic CDN', + pro: 'Smart CDN', + team: 'Smart CDN', + enterprise: 'Smart CDN', + }, + usage_based: false, + }, { title: 'Image Transformations', tooltips: { diff --git a/packages/ui-patterns/AssistantChat/AssistantChatCommands.stories.tsx b/packages/ui-patterns/AssistantChat/AssistantChatCommands.stories.tsx new file mode 100644 index 00000000000..115209b17c4 --- /dev/null +++ b/packages/ui-patterns/AssistantChat/AssistantChatCommands.stories.tsx @@ -0,0 +1,90 @@ +import { StoryObj } from '@storybook/react' +import { AssistantChatForm } from './AssistantChatForm' +import { AssistantCommandsPopover } from './AssistantCommandsPopover' +import { Box, User } from 'lucide-react' +import { createRef, useRef, useState } from 'react' + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +export default { + title: 'AI/Assistant Chat', + component: AssistantChatForm, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + decorators: [ + (Story: any) => { + return ( +
    + +
    + ) + }, + ], + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + // argTypes: {}, +} + +// export default meta + +type Story = StoryObj + +export const CommandsPopover: Story = { + render: function Render(args) { + const [commandsOpen, setCommandsOpen] = useState(false) + const textAreaRef = createRef() + const [value, setValueState] = useState('') + const [loading, setLoading] = useState(false) + + function handleSubmit(event: React.FormEvent) { + // set loading for 3 seconds and then reset + setLoading(true) + setTimeout(() => { + setLoading(false) + }, 1500) + } + + const suggestions = [ + 'Add policy for org Inserted User Access', + 'Add policy for User-Specific Todo Access', + 'Add policy for Org Update Restriction', + ] + + return ( + <> + setValueState(e)} + suggestions={suggestions} + > + setValueState(e.target.value)} + commandsOpen={commandsOpen} + setCommandsOpen={setCommandsOpen} + onSubmit={async (event) => { + event.preventDefault() + handleSubmit(event) + }} + /> + +

    + Press / to open + commands +

    + + ) + }, + args: { + // placeholder: 'Ask AI a question...', + }, +} diff --git a/packages/ui-patterns/AssistantChat/AssistantChatForm.stories.tsx b/packages/ui-patterns/AssistantChat/AssistantChatForm.stories.tsx new file mode 100644 index 00000000000..cb643aeaac2 --- /dev/null +++ b/packages/ui-patterns/AssistantChat/AssistantChatForm.stories.tsx @@ -0,0 +1,66 @@ +import { StoryObj } from '@storybook/react' +import { AssistantChatForm } from './AssistantChatForm' +import { Box, User } from 'lucide-react' +import { createRef, useRef, useState } from 'react' + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +export default { + title: 'AI/Assistant Chat', + component: AssistantChatForm, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + decorators: [ + (Story: any) => { + return ( +
    + +
    + ) + }, + ], + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + // argTypes: {}, +} + +// export default meta + +type Story = StoryObj + +export const Primary: Story = { + render: function Render(args) { + const textAreaRef = createRef() + const [value, setValueState] = useState('') + const [loading, setLoading] = useState(false) + + function handleSubmit(event: React.FormEvent) { + // set loading for 3 seconds and then reset + setLoading(true) + setTimeout(() => { + setLoading(false) + }, 1500) + } + + return ( + } + value={value} + loading={loading} + disabled={loading} + onValueChange={(e) => setValueState(e.target.value)} + onSubmit={async (event) => { + event.preventDefault() + handleSubmit(event) + }} + /> + ) + }, + args: { + // placeholder: 'Ask AI a question...', + }, +} diff --git a/packages/ui-patterns/AssistantChat/AssistantChatForm.tsx b/packages/ui-patterns/AssistantChat/AssistantChatForm.tsx new file mode 100644 index 00000000000..4f4190aa723 --- /dev/null +++ b/packages/ui-patterns/AssistantChat/AssistantChatForm.tsx @@ -0,0 +1,148 @@ +import { Loader2 } from 'lucide-react' +import React, { ChangeEvent, createRef, useEffect } from 'react' +import { TextArea } from 'ui/src/components/shadcn/ui/text-area' +import { cn } from 'ui/src/lib/utils' + +export interface FormProps extends React.FormHTMLAttributes { + /* The ref for the textarea */ + textAreaRef: React.RefObject + /* The loading state of the form */ + loading: boolean + /* The disabled state of the form */ + disabled?: boolean + /* The value of the textarea */ + value?: string + /* The function to handle the value change */ + onValueChange: (value: ChangeEvent) => void + /* Used to stop onSubmit event when Command popover is open. Use with AssistantCommandsPopover */ + commandsOpen?: boolean + /* Used to close Command popover when onSubmit event happens. Use with AssistantCommandsPopover */ + setCommandsOpen?: (value: boolean) => void + /* The icon to display on the left of the textarea */ + icon?: React.ReactNode + /* The function to handle the form submission */ + onSubmit: React.FormHTMLAttributes['onSubmit'] +} + +const AssistantChatForm = React.forwardRef( + ( + { + loading = false, + disabled = false, + value = '', + textAreaRef, + commandsOpen = false, + icon = null, + onValueChange, + setCommandsOpen, + onSubmit, + ...props + }, + ref + ) => { + const formRef = createRef() + const submitRef = createRef() + + /** + * This effect is used to resize the textarea based on the content + */ + useEffect(() => { + if (textAreaRef) { + if (!value && textAreaRef && textAreaRef.current) { + textAreaRef.current.style.height = '40px' + } else if (textAreaRef && textAreaRef.current) { + const newHeight = textAreaRef.current.scrollHeight + 'px' + textAreaRef.current.style.height = newHeight + } + } + }, [value, textAreaRef]) + + /** + * This effect is used to focus the textarea when the component mounts + */ + useEffect(() => { + textAreaRef?.current?.focus() + }, [value, textAreaRef]) + + /** + * This function is used to handle the "Enter" key press + */ + const handleKeyDown = (event: React.KeyboardEvent) => { + // Check if the pressed key is "Enter" (key code 13) without the "Shift" key + // also checks if the commands popover is open + if (event.key === 'Enter' && !event.shiftKey && !commandsOpen) { + event.preventDefault() + if (submitRef.current) { + submitRef.current.click() + } + } + + // handles closing the commands popover if open + if (event.key === 'Enter' && commandsOpen) { + if (setCommandsOpen) setCommandsOpen(false) + } + } + + return ( +
    + {icon && ( +
    + {icon} +
    + )} +
    - -