From be363d8d914d458e920cd74ec9b92a109c31dc35 Mon Sep 17 00:00:00 2001 From: jasonwcfan Date: Tue, 6 Aug 2024 21:55:08 -0400 Subject: [PATCH] added auth --- frontend/package.json | 6 +- frontend/src/app/layout.tsx | 69 +++++-- frontend/src/context/UserStateContext.tsx | 124 ----------- frontend/src/hooks/useAuth.tsx | 194 ++++++++++++++++++ frontend/src/hooks/useWorkflow.tsx | 7 +- .../src/subframe/components/EditorTopBar.tsx | 4 +- frontend/tsconfig.json | 5 +- frontend/yarn.lock | 126 +++++++++++- 8 files changed, 384 insertions(+), 151 deletions(-) delete mode 100644 frontend/src/context/UserStateContext.tsx create mode 100644 frontend/src/hooks/useAuth.tsx diff --git a/frontend/package.json b/frontend/package.json index 3fb3763b3..eebe60dc8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,11 +10,15 @@ }, "dependencies": { "@subframe/core": "1.119.0", + "@supabase/auth-ui-react": "^0.4.7", + "@supabase/auth-ui-shared": "^0.1.8", + "@supabase/supabase-js": "^2.45.1", "@xyflow/react": "^12.0.4", "classnames": "2.3.2", "next": "14.2.5", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "uuid": "^10.0.0" }, "devDependencies": { "@types/node": "22.1.0", diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index b82daa0ad..446467723 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -3,29 +3,66 @@ import { Inter } from "next/font/google"; import "./globals.css"; import {ReactFlowProvider} from "@xyflow/react" -import React from "react"; +import React, { useEffect } from "react"; +import { useAuth } from "@/hooks/useAuth"; +import { Auth } from "@supabase/auth-ui-react"; +import { ThemeSupa } from "@supabase/auth-ui-shared"; const inter = Inter({ subsets: ["latin"] }); -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { + const { useLocalStorage, UserStateProvider, supabase } = useAuth(); + const [session, setSession] = useLocalStorage("session", null); + + useEffect(() => { + supabase.auth.getSession().then(({ data: { session } }: any) => { + setSession(session); + }); + + // const { + // data: { subscription } + // } = supabase.auth.onAuthStateChange((_event: any, session: any) => { + // setSession(session); + // }); + + // return () => subscription.unsubscribe(); + }, []); + + const renderAuth = () => { + return ( +
+
+ +
+
+ ); + }; + + const renderApp = () => { + return ( + + + {children} + + + ); + } + return ( - - - - - + + + - - - {children} - - + + {session ? renderApp() : renderAuth()} + ); } diff --git a/frontend/src/context/UserStateContext.tsx b/frontend/src/context/UserStateContext.tsx deleted file mode 100644 index 1bef3b864..000000000 --- a/frontend/src/context/UserStateContext.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import type { PropsWithChildren, ReactNode } from "react"; -import { createContext, useContext, useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; -import supabase from "../lib/supabaseClient"; -import { v4 as uuidv4 } from "uuid"; -import { authState } from "@feathery/react/dist/auth/LoginForm"; - -interface UserStateContextProps { - isLoggedIn: boolean; - bearer: any; - email: any; - avatarUrl: any; - appId: any; - userId: any; - authStateLoading: boolean; - authState: any; -} - -const UserStateContext = createContext(undefined!); - -interface UserStateProviderProps { - children: ReactNode | undefined; - session: any; // Use a more specific type if you know the structure of your session object -} - -export function UserStateProvider({ - children, - session, -}: UserStateProviderProps) { - const [bearer, setBearer] = useState(null); - const [email, setEmail] = useState(null); - const [avatarUrl, setAvatarUrl] = useState(null); - const [appId, setAppId] = useState(null); - const [userId, setUserId] = useState(""); - const loggedIn = session !== null; - const [authStateLoading, setAuthStateLoading] = useState(true); - - const fetchData = async () => { - // TODO #1: Replace with your JWT template name - console.log("fetching data"); - try { - const { - data: { user }, - } = await supabase.auth.getUser(); - let metadata = user!.user_metadata; - console.log(metadata); - const email = user!.email || metadata.email; - const id = user!.id; - // Select the row corresponding to this userId - const { data } = await supabase.from("user").select().eq("id", id); - console.log(data); - - if (data && data[0]) { - setBearer(data[0].secret_key); - setEmail(email); - setAvatarUrl(data[0].avatar_url); - setAppId(data[0].app_id); - setUserId(id); - setAuthStateLoading(false); - } else { - // Create the user row if it doesn't exist - - const response = await supabase - .from("user") - .insert({ - id: id, - secret_key: uuidv4(), - app_id: uuidv4(), - email: email, - avatar_url: metadata.avatar_url, - }) - .select(); - console.log(response); - - if (response.data && response.data[0]) { - const data = response.data[0]; - setBearer(data.secret_key); - setEmail(email); - setAvatarUrl(metadata.avatar_url); - setAppId(data.app_id); - setUserId(id); - setAuthStateLoading(false); - } - } - } catch (error) { - console.log(error); - setAuthStateLoading(false); - } - }; - - useEffect(() => { - if (session) { - fetchData(); - } - }, [session]); - - return ( - - {children} - - ); -} - -export function useUserStateContext(): UserStateContextProps { - const context = useContext(UserStateContext); - - return context; -} - diff --git a/frontend/src/hooks/useAuth.tsx b/frontend/src/hooks/useAuth.tsx new file mode 100644 index 000000000..e02c19914 --- /dev/null +++ b/frontend/src/hooks/useAuth.tsx @@ -0,0 +1,194 @@ +"use client"; + +import { useState, useEffect, createContext, useContext, PropsWithChildren, ReactNode } from 'react'; +import { v4 as uuidv4 } from "uuid"; +import { createClient } from "@supabase/supabase-js"; + +const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; +const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_KEY; + +console.log("supabaseUrl", supabaseUrl); +console.log("supabaseKey", supabaseKey); + +if (!supabaseUrl) { + throw new Error("Missing env.SUPABASE_URL"); +} else if (!supabaseKey) { + throw new Error("Missing env.SUPABASE_KEY"); +} + +export const supabase = createClient(supabaseUrl, supabaseKey); + +interface UserStateContextProps { + isLoggedIn: boolean; + bearer: any; + email: any; + avatarUrl: any; + appId: any; + userId: any; + authStateLoading: boolean; + authState: any; +} + +const UserStateContext = createContext(undefined!); + +export function useAuth() { + + function logOut() { + console.log("logging out"); + supabase.auth.signOut(); + } + + const UserStateContext = createContext(undefined!); + + interface UserStateProviderProps { + children: ReactNode | undefined; + session: any; // Use a more specific type if you know the structure of your session object + } + + function UserStateProvider({ + children, + session, + }: UserStateProviderProps) { + const [bearer, setBearer] = useState(null); + const [email, setEmail] = useState(null); + const [avatarUrl, setAvatarUrl] = useState(null); + const [appId, setAppId] = useState(null); + const [userId, setUserId] = useState(""); + const loggedIn = session !== null; + const [authStateLoading, setAuthStateLoading] = useState(true); + + const fetchData = async () => { + // TODO #1: Replace with your JWT template name + console.log("fetching data"); + try { + const { + data: { user }, + } = await supabase.auth.getUser(); + let metadata = user!.user_metadata; + const email = user!.email || metadata.email; + const id = user!.id; + // Select the row corresponding to this userId + const { data } = await supabase.from("user").select().eq("id", id); + console.log(data); + + if (data && data[0]) { + setBearer(data[0].secret_key); + setEmail(email); + setAvatarUrl(data[0].avatar_url); + setAppId(data[0].app_id); + setUserId(id); + setAuthStateLoading(false); + } else { + // Create the user row if it doesn't exist + + const response = await supabase + .from("user") + .insert({ + id: id, + secret_key: uuidv4(), + app_id: uuidv4(), + email: email, + avatar_url: metadata.avatar_url, + }) + .select(); + console.log(response); + + if (response.data && response.data[0]) { + const data = response.data[0]; + setBearer(data.secret_key); + setEmail(email); + setAvatarUrl(metadata.avatar_url); + setAppId(data.app_id); + setUserId(id); + setAuthStateLoading(false); + } + } + } catch (error) { + console.log(error); + setAuthStateLoading(false); + } + }; + + useEffect(() => { + if (session) { + fetchData(); + } + }, [session]); + + return ( + + {children} + + ); + } + + function useUserStateContext(): UserStateContextProps { + const context = useContext(UserStateContext); + + return context; + } + + function useLocalStorage(key: string, initialValue: any) { + const [storedValue, setStoredValue] = useState(() => { + if (typeof window === "undefined") { + return initialValue; + } + try { + const item = window.localStorage.getItem(key); + return item ? JSON.parse(item) : initialValue; + } catch (error) { + console.error("Error reading from localStorage:", error); + return initialValue; + } + }); + + const setValue = (value: any) => { + try { + const valueToStore = + value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + console.error("Error writing to localStorage:", error); + } + }; + + useEffect(() => { + const handleStorageChange = (e: any) => { + if (e.key === key) { + setStoredValue(JSON.parse(e.newValue)); + } + }; + + window.addEventListener("storage", handleStorageChange); + return () => { + window.removeEventListener("storage", handleStorageChange); + }; + }, [key]); + + return [storedValue, setValue]; + } + + return { + logOut, + supabase, + useLocalStorage, + UserStateProvider, + useUserStateContext + }; +} \ No newline at end of file diff --git a/frontend/src/hooks/useWorkflow.tsx b/frontend/src/hooks/useWorkflow.tsx index 7f0ce43d2..dd7925d93 100644 --- a/frontend/src/hooks/useWorkflow.tsx +++ b/frontend/src/hooks/useWorkflow.tsx @@ -21,7 +21,7 @@ export default function useWorkflow() { const [workflow, setWorkflow] = useState(null); useEffect(() => { - fetch('/api/workflow') + fetch('/get-workflow') .then((res) => res.json()) .then((data) => setWorkflow(data)); }, []); @@ -35,14 +35,13 @@ export default function useWorkflow() { } const runWorkflow = async () => { - const response = await fetch('/api/workflow', { + const response = await fetch('/run-workflow', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ - workflow_id: workflow?.id, - options: {}, + id: workflow?.id }), }); const data = await response.json(); diff --git a/frontend/src/subframe/components/EditorTopBar.tsx b/frontend/src/subframe/components/EditorTopBar.tsx index 51414ae17..4621c2f9f 100644 --- a/frontend/src/subframe/components/EditorTopBar.tsx +++ b/frontend/src/subframe/components/EditorTopBar.tsx @@ -18,6 +18,7 @@ import { Avatar } from "./Avatar"; import { IconButton } from "./IconButton"; import { DropdownMenu } from "./DropdownMenu"; import { Button } from "./Button"; +import { useAuth } from "@/hooks/useAuth"; interface EditorTopBarRootProps extends React.HTMLAttributes { className?: string; @@ -28,6 +29,7 @@ const EditorTopBarRoot = React.forwardRef( { className, ...otherProps }: EditorTopBarRootProps, ref ) { + const { logOut } = useAuth(); return (
( - +
); diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 39e77f615..4105c5c84 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -38,5 +38,8 @@ ], "exclude": [ "node_modules" - ] + ], + "types": [ + "@types/uuid" + ], } \ No newline at end of file diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1303cdf16..bbc2f88a5 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -902,6 +902,11 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1" integrity sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA== +"@stitches/core@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@stitches/core/-/core-1.2.8.tgz#dce3b8fdc764fbc6dbea30c83b73bfb52cf96173" + integrity sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg== + "@subframe/core@1.119.0": version "1.119.0" resolved "https://registry.yarnpkg.com/@subframe/core/-/core-1.119.0.tgz#3532755bccfd01bdbb3bb7f24c42b37642a9c2b6" @@ -930,6 +935,79 @@ optionalDependencies: "@rollup/rollup-linux-x64-gnu" "4.13.0" +"@supabase/auth-js@2.64.4": + version "2.64.4" + resolved "https://registry.yarnpkg.com/@supabase/auth-js/-/auth-js-2.64.4.tgz#f27fdabf1ebd1b532ceb57e8bbe66969ee09cfba" + integrity sha512-9ITagy4WP4FLl+mke1rchapOH0RQpf++DI+WSG2sO1OFOZ0rW3cwAM0nCrMOxu+Zw4vJ4zObc08uvQrXx590Tg== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/auth-ui-react@^0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@supabase/auth-ui-react/-/auth-ui-react-0.4.7.tgz#6e3f941fc82a9798ba2033fab865a9f5fdfa0d32" + integrity sha512-Lp4FQGFh7BMX1Y/BFaUKidbryL7eskj1fl6Lby7BeHrTctbdvDbCMjVKS8wZ2rxuI8FtPS2iU900fSb70FHknQ== + dependencies: + "@stitches/core" "^1.2.8" + "@supabase/auth-ui-shared" "0.1.8" + prop-types "^15.7.2" + react "^18.2.0" + react-dom "^18.2.0" + +"@supabase/auth-ui-shared@0.1.8", "@supabase/auth-ui-shared@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@supabase/auth-ui-shared/-/auth-ui-shared-0.1.8.tgz#1ce63c4ac58f29d7c76436b774b0e8809dd08617" + integrity sha512-ouQ0DjKcEFg+0gZigFIEgu01V3e6riGZPzgVD0MJsCBNsMsiDT74+GgCEIElMUpTGkwSja3xLwdFRFgMNFKcjg== + +"@supabase/functions-js@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@supabase/functions-js/-/functions-js-2.4.1.tgz#373e75f8d3453bacd71fb64f88d7a341d7b53ad7" + integrity sha512-8sZ2ibwHlf+WkHDUZJUXqqmPvWQ3UHN0W30behOJngVh/qHHekhJLCFbh0AjkE9/FqqXtf9eoVvmYgfCLk5tNA== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/node-fetch@2.6.15", "@supabase/node-fetch@^2.6.14": + version "2.6.15" + resolved "https://registry.yarnpkg.com/@supabase/node-fetch/-/node-fetch-2.6.15.tgz#731271430e276983191930816303c44159e7226c" + integrity sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ== + dependencies: + whatwg-url "^5.0.0" + +"@supabase/postgrest-js@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.15.8.tgz#827aaa408cdbc89e67d0a758e7a545ac86e34312" + integrity sha512-YunjXpoQjQ0a0/7vGAvGZA2dlMABXFdVI/8TuVKtlePxyT71sl6ERl6ay1fmIeZcqxiuFQuZw/LXUuStUG9bbg== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/realtime-js@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.10.2.tgz#c2b42d17d723d2d2a9146cfad61dc3df1ce3127e" + integrity sha512-qyCQaNg90HmJstsvr2aJNxK2zgoKh9ZZA8oqb7UT2LCh3mj9zpa3Iwu167AuyNxsxrUE8eEJ2yH6wLCij4EApA== + dependencies: + "@supabase/node-fetch" "^2.6.14" + "@types/phoenix" "^1.5.4" + "@types/ws" "^8.5.10" + ws "^8.14.2" + +"@supabase/storage-js@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.6.0.tgz#0fa5e04db760ed7f78e4394844a6d409e537adc5" + integrity sha512-REAxr7myf+3utMkI2oOmZ6sdplMZZ71/2NEIEMBZHL9Fkmm3/JnaOZVSRqvG4LStYj2v5WhCruCzuMn6oD/Drw== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/supabase-js@^2.45.1": + version "2.45.1" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.45.1.tgz#38992923e4150dc5d8f99fda02c9f81bf0d5a4d6" + integrity sha512-/PVe3lXmalazD8BGMIoI7+ttvT1mLXy13lNcoAPtjP1TDDY83g8csZbVR6l+0/RZtvJxl3LGXfTJT4bjWgC5Nw== + dependencies: + "@supabase/auth-js" "2.64.4" + "@supabase/functions-js" "2.4.1" + "@supabase/node-fetch" "2.6.15" + "@supabase/postgrest-js" "1.15.8" + "@supabase/realtime-js" "2.10.2" + "@supabase/storage-js" "2.6.0" + "@swc/counter@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" @@ -1026,13 +1104,18 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/node@22.1.0": +"@types/node@*", "@types/node@22.1.0": version "22.1.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.1.0.tgz#6d6adc648b5e03f0e83c78dc788c2b037d0ad94b" integrity sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw== dependencies: undici-types "~6.13.0" +"@types/phoenix@^1.5.4": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.5.tgz#5654e14ec7ad25334a157a20015996b6d7d2075e" + integrity sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w== + "@types/prop-types@*": version "15.7.12" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" @@ -1053,6 +1136,13 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/ws@^8.5.10": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== + dependencies: + "@types/node" "*" + "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a" @@ -3141,7 +3231,7 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -3167,7 +3257,7 @@ react-day-picker@^9.0.4: dependencies: date-fns "^3.6.0" -react-dom@^18: +react-dom@^18, react-dom@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -3243,7 +3333,7 @@ react-virtualized-auto-sizer@^1.0.20: resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz#3ebdc92f4b05ad65693b3cc8e7d8dd54924c0227" integrity sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg== -react@^18: +react@^18, react@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -3684,6 +3774,11 @@ toggle-selection@^1.0.6: resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-api-utils@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -3817,6 +3912,11 @@ util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + victory-vendor@^36.6.8: version "36.9.2" resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801" @@ -3837,6 +3937,19 @@ victory-vendor@^36.6.8: d3-time "^3.0.0" d3-timer "^3.0.1" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -3922,6 +4035,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@^8.14.2: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + yaml@^2.3.4: version "2.5.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d"