diff --git a/packages/dashboard-v2/gatsby-browser.js b/packages/dashboard-v2/gatsby-browser.js index a39bdb48..79b58e24 100644 --- a/packages/dashboard-v2/gatsby-browser.js +++ b/packages/dashboard-v2/gatsby-browser.js @@ -7,13 +7,16 @@ import "@fontsource/source-sans-pro/400.css"; // normal import "@fontsource/source-sans-pro/600.css"; // semibold import "./src/styles/global.css"; import { MODAL_ROOT_ID } from "./src/components/Modal"; +import { PortalSettingsProvider } from "./src/contexts/portal-settings"; export function wrapPageElement({ element, props }) { const Layout = element.type.Layout ?? React.Fragment; return ( - - {element} -
- + + + {element} +
+ + ); } diff --git a/packages/dashboard-v2/gatsby-ssr.js b/packages/dashboard-v2/gatsby-ssr.js index a39bdb48..79b58e24 100644 --- a/packages/dashboard-v2/gatsby-ssr.js +++ b/packages/dashboard-v2/gatsby-ssr.js @@ -7,13 +7,16 @@ import "@fontsource/source-sans-pro/400.css"; // normal import "@fontsource/source-sans-pro/600.css"; // semibold import "./src/styles/global.css"; import { MODAL_ROOT_ID } from "./src/components/Modal"; +import { PortalSettingsProvider } from "./src/contexts/portal-settings"; export function wrapPageElement({ element, props }) { const Layout = element.type.Layout ?? React.Fragment; return ( - - {element} -
- + + + {element} +
+ + ); } diff --git a/packages/dashboard-v2/package.json b/packages/dashboard-v2/package.json index 44f7595d..b760bf48 100644 --- a/packages/dashboard-v2/package.json +++ b/packages/dashboard-v2/package.json @@ -39,7 +39,7 @@ "react-dropzone": "^12.0.4", "react-helmet": "^6.1.0", "react-use": "^17.3.2", - "skynet-js": "^3.0.2", + "skynet-js": "4.0.27-beta", "swr": "^1.2.2", "tailwindcss": "^3.0.23", "yup": "^0.32.11" diff --git a/packages/dashboard-v2/src/components/LoadingIndicator/FullScreenLoadingIndicator.js b/packages/dashboard-v2/src/components/LoadingIndicator/FullScreenLoadingIndicator.js new file mode 100644 index 00000000..ad261e2e --- /dev/null +++ b/packages/dashboard-v2/src/components/LoadingIndicator/FullScreenLoadingIndicator.js @@ -0,0 +1,7 @@ +import { ContainerLoadingIndicator } from "./ContainerLoadingIndicator"; + +export const FullScreenLoadingIndicator = () => ( +
+ +
+); diff --git a/packages/dashboard-v2/src/components/LoadingIndicator/index.js b/packages/dashboard-v2/src/components/LoadingIndicator/index.js index df7c2a88..5e7f91f4 100644 --- a/packages/dashboard-v2/src/components/LoadingIndicator/index.js +++ b/packages/dashboard-v2/src/components/LoadingIndicator/index.js @@ -1 +1,2 @@ export * from "./ContainerLoadingIndicator"; +export * from "./FullScreenLoadingIndicator"; diff --git a/packages/dashboard-v2/src/components/NavBar/NavBar.js b/packages/dashboard-v2/src/components/NavBar/NavBar.js index 65d9afe5..f75030bb 100644 --- a/packages/dashboard-v2/src/components/NavBar/NavBar.js +++ b/packages/dashboard-v2/src/components/NavBar/NavBar.js @@ -2,6 +2,7 @@ import { Link, navigate } from "gatsby"; import styled from "styled-components"; import { screen } from "../../lib/cssHelpers"; +import { useUser } from "../../contexts/user"; import { DropdownMenu, DropdownMenuLink } from "../DropdownMenu"; import { CogIcon, LockClosedIcon, SkynetLogoIcon } from "../Icons"; import { PageContainer } from "../PageContainer"; @@ -49,48 +50,60 @@ const NavBarBody = styled.nav.attrs({ } `; -export const NavBar = () => ( - - - - - - - - - Dashboard - - - Files - - - Payments - - - - - - { - await accountsService.post("logout"); - navigate("/auth/login"); - // TODO: handle errors - }} - activeClassName="text-primary" - className="cursor-pointer" - icon={LockClosedIcon} - label="Log out" - /> - - - - - -); +export const NavBar = () => { + const { mutate: setUserState } = useUser(); + + const onLogout = async () => { + try { + await accountsService.post("logout"); + // Don't refresh user state from server, as it will now respond with UNAUTHORIZED + // and user will be redirected to /auth/login with return_to query param (which we want empty). + await setUserState(null, { revalidate: false }); + navigate("/auth/login"); + } catch { + // Do nothing. + } + }; + + return ( + + + + + + + + + Dashboard + + + Files + + + Payments + + + + + + + + + + + + ); +}; diff --git a/packages/dashboard-v2/src/components/Slider/Slider.js b/packages/dashboard-v2/src/components/Slider/Slider.js index 973b9941..33c3bc2a 100644 --- a/packages/dashboard-v2/src/components/Slider/Slider.js +++ b/packages/dashboard-v2/src/components/Slider/Slider.js @@ -40,7 +40,8 @@ const Slider = ({ slides, breakpoints, scrollerClassName, className }) => { ); React.useEffect(() => { - const maxIndex = slides.length - visibleSlides; + // Prevent negative values for activeIndex. + const maxIndex = Math.max(slides.length - visibleSlides, 0); // Make sure to not scroll too far when screen size changes. if (activeIndex > maxIndex) { diff --git a/packages/dashboard-v2/src/components/Uploader/UploaderItem.js b/packages/dashboard-v2/src/components/Uploader/UploaderItem.js index 4f47809c..8ea279d6 100644 --- a/packages/dashboard-v2/src/components/Uploader/UploaderItem.js +++ b/packages/dashboard-v2/src/components/Uploader/UploaderItem.js @@ -5,12 +5,10 @@ import { StatusCodes } from "http-status-codes"; import copy from "copy-text-to-clipboard"; import path from "path-browserify"; import { useTimeoutFn } from "react-use"; -import { SkynetClient } from "skynet-js"; import { ProgressBar } from "./ProgressBar"; import UploaderItemIcon from "./UploaderItemIcon"; import buildUploadErrorMessage from "./buildUploadErrorMessage"; - -const skynetClient = new SkynetClient("https://siasky.net"); //TODO: proper API url +import skynetClient from "../../services/skynetClient"; const getFilePath = (file) => file.webkitRelativePath || file.path || file.name; diff --git a/packages/dashboard-v2/src/components/forms/SignUpForm.js b/packages/dashboard-v2/src/components/forms/SignUpForm.js index 976c0c74..6725c673 100644 --- a/packages/dashboard-v2/src/components/forms/SignUpForm.js +++ b/packages/dashboard-v2/src/components/forms/SignUpForm.js @@ -61,11 +61,6 @@ export const SignUpForm = ({ onSuccess, onFailure }) => ( > {({ errors, touched }) => (
-
-

Create your free account

-

Includes 100 GB storage at basic speed

-
- { - const sortedPlans = [freePlan, ...plans].sort((planA, planB) => planA.tier - planB.tier); +const aggregatePlansAndLimits = (plans, limits, { includeFreePlan }) => { + const allPlans = includeFreePlan ? [freePlan, ...plans] : [...plans]; + const sortedPlans = allPlans.sort((planA, planB) => planA.tier - planB.tier); // Decorate each plan with its corresponding limits data, if available. if (limits?.length) { @@ -26,10 +28,11 @@ const aggregatePlansAndLimits = (plans, limits) => { }; export const PlansProvider = ({ children }) => { - const { data: rawPlans, error: plansError } = useSWR("stripe/prices"); - const { data: limits, error: limitsError } = useSWR("limits"); + const { settings } = usePortalSettings(); + const { data: rawPlans, error: plansError } = useSWRImmutable("stripe/prices"); + const { data: limits, error: limitsError } = useSWRImmutable("limits"); - const [plans, setPlans] = useState([freePlan]); + const [plans, setPlans] = useState(settings.isSubscriptionRequired ? [] : [freePlan]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -39,9 +42,11 @@ export const PlansProvider = ({ children }) => { setError(plansError || limitsError); } else if (rawPlans) { setLoading(false); - setPlans(aggregatePlansAndLimits(rawPlans, limits?.userLimits)); + setPlans( + aggregatePlansAndLimits(rawPlans, limits?.userLimits, { includeFreePlan: !settings.isSubscriptionRequired }) + ); } - }, [rawPlans, limits, plansError, limitsError]); + }, [rawPlans, limits, plansError, limitsError, settings.isSubscriptionRequired]); return {children}; }; diff --git a/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsContext.js b/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsContext.js new file mode 100644 index 00000000..4c0cf185 --- /dev/null +++ b/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsContext.js @@ -0,0 +1,9 @@ +import { createContext } from "react"; + +export const defaultSettings = { + areAccountsEnabled: false, + isAuthenticationRequired: false, + isSubscriptionRequired: false, +}; + +export const PortalSettingsContext = createContext(defaultSettings); diff --git a/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsProvider.js b/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsProvider.js new file mode 100644 index 00000000..a5a033c8 --- /dev/null +++ b/packages/dashboard-v2/src/contexts/portal-settings/PortalSettingsProvider.js @@ -0,0 +1,39 @@ +import { useEffect, useState } from "react"; +import useSWRImmutable from "swr/immutable"; + +import skynetClient from "../../services/skynetClient"; + +import { defaultSettings, PortalSettingsContext } from "./PortalSettingsContext"; + +const fetcher = async (path) => { + try { + const baseUrl = await skynetClient.portalUrl(); + + return fetch(`${baseUrl}/${path}`).then((response) => response.json()); + } catch (error) { + return fetch(path).then((response) => response.json()); + } +}; + +export const PortalSettingsProvider = ({ children }) => { + const { data, error } = useSWRImmutable("/__internal/do/not/use/accounts", fetcher); + const [loading, setLoading] = useState(true); + const [settings, setSettings] = useState(defaultSettings); + + useEffect(() => { + if (data || error) { + setLoading(false); + } + if (data) { + setSettings({ + areAccountsEnabled: data.enabled, + isAuthenticationRequired: data.auth_required, + isSubscriptionRequired: data.subscription_required, + }); + } + }, [data, error]); + + return ( + {children} + ); +}; diff --git a/packages/dashboard-v2/src/contexts/portal-settings/index.js b/packages/dashboard-v2/src/contexts/portal-settings/index.js new file mode 100644 index 00000000..c560bb5c --- /dev/null +++ b/packages/dashboard-v2/src/contexts/portal-settings/index.js @@ -0,0 +1,2 @@ +export * from "./PortalSettingsProvider"; +export * from "./usePortalSettings"; diff --git a/packages/dashboard-v2/src/contexts/portal-settings/usePortalSettings.js b/packages/dashboard-v2/src/contexts/portal-settings/usePortalSettings.js new file mode 100644 index 00000000..1614eb95 --- /dev/null +++ b/packages/dashboard-v2/src/contexts/portal-settings/usePortalSettings.js @@ -0,0 +1,5 @@ +import { useContext } from "react"; + +import { PortalSettingsContext } from "./PortalSettingsContext"; + +export const usePortalSettings = () => useContext(PortalSettingsContext); diff --git a/packages/dashboard-v2/src/contexts/user/UserProvider.js b/packages/dashboard-v2/src/contexts/user/UserProvider.js index 4d1efac5..bb10ffe4 100644 --- a/packages/dashboard-v2/src/contexts/user/UserProvider.js +++ b/packages/dashboard-v2/src/contexts/user/UserProvider.js @@ -1,10 +1,10 @@ import { useEffect, useState } from "react"; -import useSWR from "swr"; +import useSWRImmutable from "swr/immutable"; import { UserContext } from "./UserContext"; export const UserProvider = ({ children }) => { - const { data: user, error, mutate } = useSWR("user"); + const { data: user, error, mutate } = useSWRImmutable("user"); const [loading, setLoading] = useState(true); useEffect(() => { diff --git a/packages/dashboard-v2/src/hooks/useUpgradeRedirect.js b/packages/dashboard-v2/src/hooks/useUpgradeRedirect.js new file mode 100644 index 00000000..5529c152 --- /dev/null +++ b/packages/dashboard-v2/src/hooks/useUpgradeRedirect.js @@ -0,0 +1,31 @@ +import { navigate } from "gatsby"; +import { useEffect, useState } from "react"; + +import { usePortalSettings } from "../contexts/portal-settings"; +import { useUser } from "../contexts/user"; +import freeTier from "../lib/tiers"; + +export default function useUpgradeRedirect() { + const [verifyingSubscription, setVerifyingSubscription] = useState(true); + const { user, loading: userDataLoading } = useUser(); + const { settings, loading: portalSettingsLoading } = usePortalSettings(); + + useEffect(() => { + setVerifyingSubscription(true); + const isDataLoaded = !userDataLoading && !portalSettingsLoading && user && settings; + const hasPaidSubscription = user.tier > freeTier.tier; + + if (isDataLoaded) { + if (settings.isSubscriptionRequired && !hasPaidSubscription) { + console.log("redirecting", user, settings); + navigate("/upgrade"); + } else { + setVerifyingSubscription(false); + } + } + }, [user, userDataLoading, settings.isSubscriptionRequired, portalSettingsLoading, settings]); + + return { + verifyingSubscription, + }; +} diff --git a/packages/dashboard-v2/src/layouts/DashboardLayout.js b/packages/dashboard-v2/src/layouts/DashboardLayout.js index b369ece3..76af9218 100644 --- a/packages/dashboard-v2/src/layouts/DashboardLayout.js +++ b/packages/dashboard-v2/src/layouts/DashboardLayout.js @@ -8,7 +8,7 @@ import { PageContainer } from "../components/PageContainer"; import { NavBar } from "../components/Navbar"; import { Footer } from "../components/Footer"; import { UserProvider, useUser } from "../contexts/user"; -import { ContainerLoadingIndicator } from "../components/LoadingIndicator"; +import { FullScreenLoadingIndicator } from "../components/LoadingIndicator"; const Wrapper = styled.div.attrs({ className: "min-h-screen overflow-hidden", @@ -24,11 +24,7 @@ const Layout = ({ children }) => { // Prevent from flashing the dashboard screen to unauthenticated users. return ( - {!user && ( -
- -
- )} + {!user && } {user && <>{children}}
); diff --git a/packages/dashboard-v2/src/lib/swrConfig.js b/packages/dashboard-v2/src/lib/swrConfig.js index 058b5ead..16e2dbfb 100644 --- a/packages/dashboard-v2/src/lib/swrConfig.js +++ b/packages/dashboard-v2/src/lib/swrConfig.js @@ -15,12 +15,15 @@ const redirectUnauthenticated = (key) => }); const redirectAuthenticated = (key) => - fetch(`${baseUrl}/${key}`).then((response) => { - if (response.status === StatusCodes.OK) { - navigate(`/`); + fetch(`${baseUrl}/${key}`).then(async (response) => { + if (response.ok) { + await navigate("/"); + return response.json(); } - return response.json(); + // If there was an error, let's throw so useSWR's "error" property is populated instead "data". + const data = await response.json(); + throw new Error(data?.message || `Error occured when trying to fetch: ${key}`); }); export const allUsers = { diff --git a/packages/dashboard-v2/src/pages/auth/login.js b/packages/dashboard-v2/src/pages/auth/login.js index e3b5240b..8b0cfbb5 100644 --- a/packages/dashboard-v2/src/pages/auth/login.js +++ b/packages/dashboard-v2/src/pages/auth/login.js @@ -1,19 +1,31 @@ +import { useEffect } from "react"; import { navigate } from "gatsby"; import AuthLayout from "../../layouts/AuthLayout"; - import { LoginForm } from "../../components/forms"; +import { useUser } from "../../contexts/user"; const LoginPage = ({ location }) => { + const { user, mutate: refreshUserState } = useUser(); const query = new URLSearchParams(location.search); const redirectTo = query.get("return_to"); + useEffect(() => { + if (user) { + navigate(redirectTo || "/"); + } + }, [user, redirectTo]); + return (
Skynet
- navigate(redirectTo || "/")} /> + { + await refreshUserState(); + }} + />
); }; diff --git a/packages/dashboard-v2/src/pages/auth/signup.js b/packages/dashboard-v2/src/pages/auth/signup.js index 4acbae85..2af428f9 100644 --- a/packages/dashboard-v2/src/pages/auth/signup.js +++ b/packages/dashboard-v2/src/pages/auth/signup.js @@ -1,10 +1,41 @@ import { useEffect, useState } from "react"; +import { navigate } from "gatsby"; +import bytes from "pretty-bytes"; import AuthLayout from "../../layouts/AuthLayout"; +import { Alert } from "../../components/Alert"; import HighlightedLink from "../../components/HighlightedLink"; import { SignUpForm } from "../../components/forms/SignUpForm"; -import { navigate } from "gatsby"; +import { usePortalSettings } from "../../contexts/portal-settings"; +import { PlansProvider, usePlans } from "../../contexts/plans"; + +const FreePortalHeader = () => { + const { plans } = usePlans(); + + const freePlan = plans.find(({ price }) => price === 0); + const freeStorage = freePlan ? bytes(freePlan.limits?.storageLimit, { binary: true }) : null; + + return ( +
+

Create your free account

+ {freeStorage &&

Includes {freeStorage} storage at basic speed

} +
+ ); +}; + +const PaidPortalHeader = () => ( +
+

Create your account

+

+ If you're looking for a free portal, try{" "} + + SkynetFree.net + {" "} + with 100GB of free storage. +

+
+); const State = { Pure: "PURE", @@ -14,40 +45,52 @@ const State = { const SignUpPage = () => { const [state, setState] = useState(State.Pure); + const { settings } = usePortalSettings(); useEffect(() => { if (state === State.Success) { - const timer = setTimeout(() => navigate("/"), 3000); + const timer = setTimeout(() => navigate(settings.isSubscriptionRequired ? "/upgrade" : "/"), 3000); return () => clearTimeout(timer); } - }, [state]); + }, [state, settings.isSubscriptionRequired]); return ( -
-
- Skynet -
- {state !== State.Success && ( - setState(State.Success)} onFailure={() => setState(State.Failure)} /> - )} - - {state === State.Success && ( -
-

Please check your inbox and confirm your email address.

-

You will be redirected to your dashboard shortly.

- Click here to go there now. + +
+
+ Skynet
- )} - {state === State.Failure && ( -

Something went wrong, please try again later.

- )} + {!settings.areAccountsEnabled && Accounts are not enabled on this portal.} -

- Already have an account? Sign in -

-
+ {settings.areAccountsEnabled && ( + <> + {settings.isSubscriptionRequired ? : } + + {state !== State.Success && ( + setState(State.Success)} onFailure={() => setState(State.Failure)} /> + )} + + {state === State.Success && ( +
+

Please check your inbox and confirm your email address.

+

You will be redirected to your dashboard shortly.

+ Click here to go there now. +
+ )} + + {state === State.Failure && ( +

Something went wrong, please try again later.

+ )} + + )} + +

+ Already have an account? Sign in +

+
+ ); }; diff --git a/packages/dashboard-v2/src/pages/index.js b/packages/dashboard-v2/src/pages/index.js index 4db97e04..1fd88651 100644 --- a/packages/dashboard-v2/src/pages/index.js +++ b/packages/dashboard-v2/src/pages/index.js @@ -12,9 +12,16 @@ import Slider from "../components/Slider/Slider"; import CurrentUsage from "../components/CurrentUsage"; import Uploader from "../components/Uploader/Uploader"; import CurrentPlan from "../components/CurrentPlan"; +import { FullScreenLoadingIndicator } from "../components/LoadingIndicator"; +import useUpgradeRedirect from "../hooks/useUpgradeRedirect"; const IndexPage = () => { const showRecentActivity = useMedia(`(min-width: ${theme.screens.md})`); + const { verifyingSubscription } = useUpgradeRedirect(); + + if (verifyingSubscription) { + return ; + } return ( diff --git a/packages/dashboard-v2/src/pages/upgrade.js b/packages/dashboard-v2/src/pages/upgrade.js index 894c8273..8e47472e 100644 --- a/packages/dashboard-v2/src/pages/upgrade.js +++ b/packages/dashboard-v2/src/pages/upgrade.js @@ -10,13 +10,11 @@ import { Panel } from "../components/Panel"; import Slider from "../components/Slider/Slider"; import { CheckmarkIcon } from "../components/Icons"; import { Button } from "../components/Button"; +import { usePortalSettings } from "../contexts/portal-settings"; +import { Alert } from "../components/Alert"; +import HighlightedLink from "../components/HighlightedLink"; -const SLIDER_BREAKPOINTS = [ - { - name: "xl", - scrollable: true, - visibleSlides: 4, - }, +const PAID_PORTAL_BREAKPOINTS = [ { name: "lg", scrollable: true, @@ -33,6 +31,15 @@ const SLIDER_BREAKPOINTS = [ }, ]; +const FREE_PORTAL_BREAKPOINTS = [ + { + name: "xl", + scrollable: true, + visibleSlides: 4, + }, + ...PAID_PORTAL_BREAKPOINTS, +]; + const PlanSummaryItem = ({ children }) => (
  • @@ -68,6 +75,7 @@ const localizedNumber = (value) => value.toLocaleString(); const PlansSlider = () => { const { user, error: userError } = useUser(); const { plans, loading, activePlan, error: plansError } = useActivePlan(user); + const { settings } = usePortalSettings(); if (userError || plansError) { return ( @@ -80,6 +88,18 @@ const PlansSlider = () => { return (
    + {settings.isSubscriptionRequired && !activePlan && ( + +

    This Skynet portal requires a paid subscription.

    +

    + If you're not ready for that yet, you can use your account on{" "} + + SkynetFree.net + {" "} + to store up to 100GB for free. +

    +
    + )} {!loading && ( { @@ -114,8 +134,7 @@ const PlansSlider = () => { ); })} - breakpoints={SLIDER_BREAKPOINTS} - scrollerClassName="gap-4 xl:gap-8" + breakpoints={settings.isSubscriptionRequired ? PAID_PORTAL_BREAKPOINTS : FREE_PORTAL_BREAKPOINTS} className="px-8 sm:px-4 md:px-0 lg:px-0" /> )} diff --git a/packages/dashboard-v2/src/services/skynetClient.js b/packages/dashboard-v2/src/services/skynetClient.js new file mode 100644 index 00000000..0549085c --- /dev/null +++ b/packages/dashboard-v2/src/services/skynetClient.js @@ -0,0 +1,3 @@ +import { SkynetClient } from "skynet-js"; + +export default new SkynetClient("https://skynetpro.net"); // TODO: proper API url diff --git a/packages/dashboard-v2/yarn.lock b/packages/dashboard-v2/yarn.lock index 52cf68b8..30d4e8e8 100644 --- a/packages/dashboard-v2/yarn.lock +++ b/packages/dashboard-v2/yarn.lock @@ -1107,7 +1107,7 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.17.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== @@ -2100,6 +2100,19 @@ escape-string-regexp "^2.0.0" lodash.deburr "^4.1.0" +"@skynetlabs/tus-js-client@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@skynetlabs/tus-js-client/-/tus-js-client-2.3.0.tgz#a14fd4197e2bc4ce8be724967a0e4c17d937cb64" + integrity sha512-piGvPlJh+Bu3Qf08bDlc/TnFLXE81KnFoPgvnsddNwTSLyyspxPFxJmHO5ki6SYyOl3HmUtGPoix+r2M2UpFEA== + dependencies: + buffer-from "^0.1.1" + combine-errors "^3.0.3" + is-stream "^2.0.0" + js-base64 "^2.6.1" + lodash.throttle "^4.1.1" + proper-lockfile "^2.0.1" + url-parse "^1.4.3" + "@storybook/addon-actions@6.4.19", "@storybook/addon-actions@^6.4.19": version "6.4.19" resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-6.4.19.tgz#10631d9c0a6669810264ea7fac3bff7201553084" @@ -4493,6 +4506,13 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +async-mutex@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.3.2.tgz#1485eda5bda1b0ec7c8df1ac2e815757ad1831df" + integrity sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA== + dependencies: + tslib "^2.3.1" + async-retry-ng@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/async-retry-ng/-/async-retry-ng-2.0.1.tgz#f5285ec1c52654a2ba6a505d0c18b1eadfaebd41" @@ -4558,13 +4578,20 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== -axios@^0.21.0, axios@^0.21.1: +axios@^0.21.1: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: follow-redirects "^1.14.0" +axios@^0.26.0: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -4827,6 +4854,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base32-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base32-decode/-/base32-decode-1.0.0.tgz#2a821d6a664890c872f20aa9aca95a4b4b80e2a7" + integrity sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g== + base32-encode@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/base32-encode/-/base32-encode-1.2.0.tgz#e150573a5e431af0a998e32bdfde7045725ca453" @@ -5109,6 +5141,11 @@ buffer-equal@0.0.1: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= +buffer-from@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0" + integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -5670,6 +5707,14 @@ colors@1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +combine-errors@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.3.tgz#f4df6740083e5703a3181110c2b10551f003da86" + integrity sha1-9N9nQAg+VwOjGBEQwrEFUfAD2oY= + dependencies: + custom-error-instance "2.1.1" + lodash.uniqby "4.5.0" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -6273,6 +6318,11 @@ csstype@^3.0.2, csstype@^3.0.6: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== +custom-error-instance@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz#3cf6391487a6629a6247eb0ca0ce00081b7e361a" + integrity sha1-PPY5FIemYppiR+sMoM4ACBt+Nho= + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -7893,6 +7943,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== +follow-redirects@^1.14.8: + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -10202,6 +10257,11 @@ jpeg-js@^0.4.0: resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== +js-base64@^2.6.1: + version "2.6.4" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" + integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -10543,6 +10603,43 @@ lodash-es@^4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash._baseiteratee@~4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz#34a9b5543572727c3db2e78edae3c0e9e66bd102" + integrity sha1-NKm1VDVycnw9sueO2uPA6eZr0QI= + dependencies: + lodash._stringtopath "~4.8.0" + +lodash._basetostring@~4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz#9327c9dc5158866b7fa4b9d42f4638e5766dd9df" + integrity sha1-kyfJ3FFYhmt/pLnUL0Y45XZt2d8= + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg= + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash._stringtopath@~4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz#941bcf0e64266e5fc1d66fed0a6959544c576824" + integrity sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ= + dependencies: + lodash._basetostring "~4.12.0" + lodash.clonedeep@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -10603,6 +10700,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -10613,6 +10715,14 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash.uniqby@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz#a3a17bbf62eeb6240f491846e97c1c4e2a5e1e21" + integrity sha1-o6F7v2LutiQPSRhG6XwcTipeHiE= + dependencies: + lodash._baseiteratee "~4.7.0" + lodash._baseuniq "~4.6.0" + lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -10969,6 +11079,11 @@ mime@^2.4.4, mime@^2.5.2: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -12159,6 +12274,11 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +post-me@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/post-me/-/post-me-0.4.5.tgz#6171b721c7b86230c51cfbe48ddea047ef8831ce" + integrity sha512-XgPdktF/2M5jglgVDULr9NUb/QNv3bY3g6RG22iTb5MIMtB07/5FJB5fbVmu5Eaopowc6uZx7K3e7x1shPwnXw== + postcss-calc@^8.2.0: version "8.2.4" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" @@ -12676,6 +12796,14 @@ prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.7.2, object-assign "^4.1.1" react-is "^16.13.1" +proper-lockfile@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-2.0.1.tgz#159fb06193d32003f4b3691dd2ec1a634aa80d1d" + integrity sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0= + dependencies: + graceful-fs "^4.1.2" + retry "^0.10.0" + proper-lockfile@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -13558,6 +13686,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -13957,24 +14090,35 @@ sjcl@^1.0.8: resolved "https://registry.yarnpkg.com/sjcl/-/sjcl-1.0.8.tgz#f2ec8d7dc1f0f21b069b8914a41a8f236b0e252a" integrity sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ== -skynet-js@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/skynet-js/-/skynet-js-3.0.2.tgz#d08a33066ee85b86e4ffc7c31591239a88da6fbe" - integrity sha512-rbmpOGbDwg2FcsZ7HkmGhVaUwWO6kaysRFKTBC3yGiV+b6fbnpPPNCskvh8kWwbTsj+koWkSRUFYqG7cc+eTuA== +skynet-js@^4.0.27-beta: + version "4.0.27-beta" + resolved "https://registry.yarnpkg.com/skynet-js/-/skynet-js-4.0.27-beta.tgz#4257bffda8757830656e0beb89d0d2e44da17e2f" + integrity sha512-JV+QE/2l2YwVN1jQHVMFXgggwtBrPAnuyXySbLgafEJAde5dUwSEr5YRMV+3LvEgYkGhxSb74pyq0u0wrF2sUg== dependencies: - "@babel/runtime" "^7.11.2" - axios "^0.21.0" + "@skynetlabs/tus-js-client" "^2.3.0" + async-mutex "^0.3.2" + axios "^0.26.0" + base32-decode "^1.0.0" base32-encode "^1.1.1" base64-js "^1.3.1" blakejs "^1.1.0" buffer "^6.0.1" - mime "^2.5.2" + mime "^3.0.0" path-browserify "^1.0.1" + post-me "^0.4.5" randombytes "^2.1.0" sjcl "^1.0.8" + skynet-mysky-utils "^0.3.0" tweetnacl "^1.0.3" url-join "^4.0.1" - url-parse "^1.4.7" + url-parse "^1.5.1" + +skynet-mysky-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/skynet-mysky-utils/-/skynet-mysky-utils-0.3.0.tgz#87fdc0a5f8547cf660280ef86b7a762269919bad" + integrity sha512-X9L6SrVTdwTUFook/E6zUWCOpXHdyspLAu0elQbbPkZCWeFpr/XXTMbiyPV3m1liYsesngAKxzaSqylaTWOGUA== + dependencies: + post-me "^0.4.5" slash@^2.0.0: version "2.0.0" @@ -15061,7 +15205,7 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.0: +tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@~2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -15419,7 +15563,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@^1.4.7: +url-parse@^1.4.3, url-parse@^1.5.1: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==