diff --git a/src/backend/Makefile b/src/backend/Makefile index ccfdf492..d391714e 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -1,17 +1,20 @@ -.PHONY: run -run: +.PHONY: dirs +dirs: mkdir -p docker-volumes/log && chmod 777 docker-volumes/log mkdir -p docker-volumes/rabbitmq/data && chmod 777 docker-volumes/rabbitmq/data mkdir -p docker-volumes/rabbitmq/log && chmod 777 docker-volumes/rabbitmq/log mkdir -p docker-volumes/mssql/data && chmod 777 docker-volumes/mssql/data mkdir -p docker-volumes/mssql/log && chmod 777 docker-volumes/mssql/log mkdir -p docker-volumes/mssql/secrets && chmod 777 docker-volumes/mssql/secrets + +.PHONY: run +run: dirs docker compose up -d --build .PHONY: clean clean: docker compose down --remove-orphans - rm -rf log rabbitmq + rm -rf docker-volumes .PHONY: wait wait: diff --git a/src/backend/README.md b/src/backend/README.md new file mode 100644 index 00000000..6a38d8b1 --- /dev/null +++ b/src/backend/README.md @@ -0,0 +1,32 @@ +# Backend local development setup + +## Start local SQL server + +```bash +cd src/backend + +# Create docker-volumes directory structure if it doesn't already exist +make dirs + +# Run SQL server +podman run --rm -e ACCEPT_EULA=Y -e SA_PASSWORD=DevelopmentOnlyPassword1 -p 1433:1433 -v .\\docker-volumes\\mssql\\data:/var/opt/mssql/data -v .\\docker-volumes\\mssql\\log:/var/opt/mssql/log -v .\\docker-volumes\\mssql\\secrets:/var/opt/mssql/secrets --name mssql-dev -it mcr.microsoft.com/mssql/server:2022-latest +``` + +## Start local backend instance + +```bash +# Windows +set ASPNETCORE_ENVIRONMENT=Development +set DB_CONNECTION="Server=127.0.0.1,1433;Initial Catalog=api;User=sa;Password=DevelopmentOnlyPassword1;TrustServerCertificate=True;" + +# Linux/mac +ASPNETCORE_ENVIRONMENT=Development +DB_CONNECTION="Server=127.0.0.1,1433;Initial Catalog=api;User=sa;Password=DevelopmentOnlyPassword1;TrustServerCertificate=True;" + +# TODO: broken due to docker compose solution file +dotnet run WebApi + +# Current method: +cd src/backend/WebApi +dotnet run -lp "https swagger" +``` diff --git a/src/frontend/.dockerignore b/src/frontend/.dockerignore index f83526d1..6178e545 100644 --- a/src/frontend/.dockerignore +++ b/src/frontend/.dockerignore @@ -1 +1,4 @@ -**/node_modules/ \ No newline at end of file +**/node_modules/ +**/dist/ +**/obj/ +**/.vscode/ \ No newline at end of file diff --git a/src/frontend/Dockerfile b/src/frontend/Dockerfile index 426e93ea..76933332 100644 --- a/src/frontend/Dockerfile +++ b/src/frontend/Dockerfile @@ -10,6 +10,9 @@ RUN yarn build FROM nginx:alpine-otel AS final RUN apk update && apk upgrade -COPY --from=build /app/dist /usr/share/nginx/html/ -EXPOSE 80 +COPY --from=build /app/dist/client /usr/share/nginx/html/ +COPY ssl/localhost.crt /etc/ssl/certs/localhost.crt +COPY ssl/localhost.key /etc/ssl/private/localhost.key +COPY nginx/default.conf /etc/nginx/conf.d/default.conf +EXPOSE 8080 8443 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/src/frontend/README.md b/src/frontend/README.md index 0d6babed..499636af 100644 --- a/src/frontend/README.md +++ b/src/frontend/README.md @@ -28,3 +28,18 @@ export default { - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list + +## Local container build and launch + +```bash +# Make localhost certificate if it's missing +# cd ssl && make && cd .. + +# Build container +podman build -f Dockerfile . -t frontend-test + +# Run container +docker run --rm -p 5173:8443 -it frontend-test + +# Navigate to https://localhost:5173/ in browser +``` diff --git a/src/frontend/cspell.json b/src/frontend/cspell.json index 05e6b440..eba42290 100644 --- a/src/frontend/cspell.json +++ b/src/frontend/cspell.json @@ -4,12 +4,16 @@ "words": [ "githubusercontent", "mkdirp", - "precached", "nocheck", + "precached", "streetsidesoftware", "tsmerge", + "vike", "visualstudio", "vsmarketplacebadge" ], - "ignorePaths": ["node_modules/**", "*.lock"] + "ignorePaths": [ + "node_modules/**", + "*.lock" + ] } diff --git a/src/frontend/nginx/default.conf b/src/frontend/nginx/default.conf new file mode 100644 index 00000000..69cfda99 --- /dev/null +++ b/src/frontend/nginx/default.conf @@ -0,0 +1,12 @@ +server { + listen 8080; + listen 8443 ssl; + server_name localhost; + ssl_certificate /etc/ssl/certs/localhost.crt; + ssl_certificate_key /etc/ssl/private/localhost.key; + + location / { + root /usr/share/nginx/html; + index index.html; + } +} diff --git a/src/frontend/package.json b/src/frontend/package.json index 183af63c..520f1ebc 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -19,7 +19,11 @@ "@tanstack/react-query-devtools": "^5.35.1", "axios": "^1.6.8", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-streaming": "^0.3.33", + "vike": "^0.4.177", + "vike-react": "^0.4.15", + "vike-react-query": "^0.1.0" }, "devDependencies": { "@cspell/eslint-plugin": "^8.9.1", diff --git a/src/frontend/src/api/endpoints/blogging/blogging.msw.ts b/src/frontend/src/api/endpoints/blogging/blogging.msw.ts index d5dd4858..e36b60a1 100644 --- a/src/frontend/src/api/endpoints/blogging/blogging.msw.ts +++ b/src/frontend/src/api/endpoints/blogging/blogging.msw.ts @@ -6,17 +6,20 @@ import type { BlogDto, PostDto } from '../../models' export const getGetBlogsResponseMock = (): BlogDto[] => Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ blogId: faker.helpers.arrayElement([faker.number.int({ min: undefined, max: undefined }), undefined]), + title: faker.helpers.arrayElement([faker.word.sample(), null]), url: faker.helpers.arrayElement([faker.word.sample(), null]), })) export const getPostBlogResponseMock = (overrideResponse: Partial = {}): BlogDto => ({ blogId: faker.helpers.arrayElement([faker.number.int({ min: undefined, max: undefined }), undefined]), + title: faker.helpers.arrayElement([faker.word.sample(), null]), url: faker.helpers.arrayElement([faker.word.sample(), null]), ...overrideResponse, }) export const getGetBlogResponseMock = (overrideResponse: Partial = {}): BlogDto => ({ blogId: faker.helpers.arrayElement([faker.number.int({ min: undefined, max: undefined }), undefined]), + title: faker.helpers.arrayElement([faker.word.sample(), null]), url: faker.helpers.arrayElement([faker.word.sample(), null]), ...overrideResponse, }) diff --git a/src/frontend/src/api/models/blogDto.ts b/src/frontend/src/api/models/blogDto.ts index c8273ec8..10ea9352 100644 --- a/src/frontend/src/api/models/blogDto.ts +++ b/src/frontend/src/api/models/blogDto.ts @@ -6,6 +6,11 @@ export interface BlogDto { /** Gets or sets the unique identifier for the blog. */ blogId?: number + /** + * Gets or sets the title of the blog. + * @nullable + */ + title: string | null /** * Gets or sets the URL of the blog. * @nullable diff --git a/src/frontend/src/main.tsx b/src/frontend/src/main.tsx deleted file mode 100644 index da15f197..00000000 --- a/src/frontend/src/main.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { ReactQueryDevtools } from '@tanstack/react-query-devtools' -import React from 'react' -import ReactDOM from 'react-dom/client' - -import App from './App.tsx' -import { AuthProvider } from './auth.context' -import './index.css' -import * as serviceWorker from './serviceWorker' - -const queryClient = new QueryClient() - -// if (process.env.NODE_ENV === 'development') { -// require('./mock'); -// } - -const rootElement = document.getElementById('root') -if (rootElement != null) { - ReactDOM.createRoot(rootElement).render( - - - - - - - - , - ) -} else { - console.error('No root element found') -} - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister() diff --git a/src/frontend/src/pages/+config.ts b/src/frontend/src/pages/+config.ts new file mode 100644 index 00000000..65563f25 --- /dev/null +++ b/src/frontend/src/pages/+config.ts @@ -0,0 +1,3 @@ +export default { + // Add settings here later +} diff --git a/src/frontend/src/pages/_error/+Page.tsx b/src/frontend/src/pages/_error/+Page.tsx new file mode 100644 index 00000000..14ec74c9 --- /dev/null +++ b/src/frontend/src/pages/_error/+Page.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import { type PageContext } from 'vike/types' +import { usePageContext } from 'vike-react/usePageContext' + +/** + * Page component. + * @returns {React.JSX.Element} The rendered component. + */ +function Page(): React.JSX.Element { + const pageContext = usePageContext() as ExtendedPageContext & PageContext + + let msg: string // Message shown to the user + const { abortReason, abortStatusCode } = pageContext + if (typeof abortReason === 'object' && abortReason?.notAdmin) { + // Handle `throw render(403, { notAdmin: true })` + msg = "You cannot access this page because you aren't an administrator." + } else if (typeof abortReason === 'string') { + // Handle `throw render(abortStatusCode, `You cannot access ${someCustomMessage}`)` + msg = abortReason + } else if (abortStatusCode === 403) { + // Handle `throw render(403)` + msg = "You cannot access this page because you don't have enough privileges." + } else if (abortStatusCode === 401) { + // Handle `throw render(401)` + msg = "You cannot access this page because you aren't logged in. Please log in." + } else { + // Fallback error message + msg = + pageContext.is404 ?? false + ? "This page doesn't exist." + : 'Something went wrong. Sincere apologies. Try again (later).' + } + + return ( +
+

{msg}

+
+ ) +} + +/** + * Center component. + * @param {Readonly<{ children: React.ReactNode }>} props - The component props. + * @returns {React.JSX.Element} The rendered component. + */ +function Center({ children }: Readonly<{ children: React.ReactNode }>): React.JSX.Element { + return ( +
+ {children} +
+ ) +} + +export interface ExtendedPageContext { + abortReason?: { notAdmin: true } | string +} + +export default Page diff --git a/src/frontend/src/pages/about/+Page.tsx b/src/frontend/src/pages/about/+Page.tsx new file mode 100644 index 00000000..c6b1e48a --- /dev/null +++ b/src/frontend/src/pages/about/+Page.tsx @@ -0,0 +1,14 @@ +import React from 'react' + +/** + * Renders the About page. + * @returns {React.JSX.Element} The rendered About page. + */ +export function Page(): React.JSX.Element { + return ( + <> +

About

+

This app showcases a migration from Vite to Vike.

+ + ) +} diff --git a/src/frontend/src/pages/blogs/+Page.tsx b/src/frontend/src/pages/blogs/+Page.tsx new file mode 100644 index 00000000..7e27abbd --- /dev/null +++ b/src/frontend/src/pages/blogs/+Page.tsx @@ -0,0 +1,30 @@ +import React from 'react' + +import { useGetBlogs } from '~/api/endpoints/blogging/blogging' +import { Link } from '~/renderer/Link' + +const BlogListView: React.FC = () => { + const { data: blogs, error, isLoading } = useGetBlogs() + + if (isLoading) return
Loading...
+ if (error != null) return
Error loading blogs
+ + return ( +
+

Blogs

+
    + {blogs?.map((blog) => ( +
  • +

    + + {blog.title} - ({blog.url}) + +

    +
  • + ))} +
+
+ ) +} + +export default BlogListView diff --git a/src/frontend/src/pages/blogs/@id/+Page.tsx b/src/frontend/src/pages/blogs/@id/+Page.tsx new file mode 100644 index 00000000..eb38727a --- /dev/null +++ b/src/frontend/src/pages/blogs/@id/+Page.tsx @@ -0,0 +1,37 @@ +import React from 'react' +import { usePageContext } from 'vike-react/usePageContext' + +import { useGetBlog, useGetPosts } from '~/api/endpoints/blogging/blogging' +import { Link } from '~/renderer/Link' + +const BlogListView: React.FC = () => { + const pageContext = usePageContext() + const id = pageContext?.routeParams?.id ?? window.location.pathname.split('/').at(-1) + const { data: blog, error: blogError, isLoading: blogIsLoading } = useGetBlog(parseInt(id ?? '0')) + const { data: posts, error: postsError, isLoading: postsIsLoading } = useGetPosts(parseInt(id ?? '0')) + + if (blogIsLoading || postsIsLoading) return
Loading...
+ if (blogError != null || blog === null || postsError != null || posts === null) return
Error loading blog
+ + return ( +
+

+ Blog: {blog?.title} - {blog?.url} +

+

Posts

+
    + {posts?.map((post) => ( +
  • +

    + + {post.title} - ({post.content}) + +

    +
  • + ))} +
+
+ ) +} + +export default BlogListView diff --git a/src/frontend/src/App.tsx b/src/frontend/src/pages/index/+Page.tsx similarity index 80% rename from src/frontend/src/App.tsx rename to src/frontend/src/pages/index/+Page.tsx index 1e060d6f..fd88cf61 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/pages/index/+Page.tsx @@ -1,19 +1,20 @@ import { type JSX, useEffect, useState } from 'react' -import './App.css' -import { useVersion } from './api/endpoints/service/service' -import { useGetWeatherForecast } from './api/endpoints/weather-forecast/weather-forecast' -import { type WeatherForecast } from './api/models' -import reactLogo from './assets/react.svg' -import { useAuthDispatch } from './auth.context' +import { useVersion } from '~/api/endpoints/service/service' +import { useGetWeatherForecast } from '~/api/endpoints/weather-forecast/weather-forecast' +import { type WeatherForecast } from '~/api/models' +import reactLogo from '~/assets/react.svg' +import { useAuthDispatch } from '~/auth.context' + +import './Page.css' import viteLogo from '/vite.svg' /** * This is the main component of the application. - * @returns {JSX.Element} The rendered App component. + * @returns {JSX.Element} The rendered Page component. */ -function App(): JSX.Element { +function Page(): JSX.Element { const [count, setCount] = useState(0) const dispatch = useAuthDispatch() const { data: weatherForecasts, refetch } = useGetWeatherForecast() @@ -67,4 +68,4 @@ function App(): JSX.Element { ) } -export default App +export default Page diff --git a/src/frontend/src/App.css b/src/frontend/src/pages/index/Page.css similarity index 100% rename from src/frontend/src/App.css rename to src/frontend/src/pages/index/Page.css diff --git a/src/frontend/src/renderer/+onRenderClient.tsx b/src/frontend/src/renderer/+onRenderClient.tsx new file mode 100644 index 00000000..7f8e0086 --- /dev/null +++ b/src/frontend/src/renderer/+onRenderClient.tsx @@ -0,0 +1,49 @@ +// https://vike.dev/onRenderClient +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { ReactQueryDevtools } from '@tanstack/react-query-devtools' +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import { type PageContext } from 'vike/types' + +import { AuthProvider } from '~/auth.context' +import * as serviceWorker from '~/serviceWorker' + +import { PageLayout } from './PageLayout' + +const queryClient = new QueryClient() + +// if (process.env.NODE_ENV === 'development') { +// require('./mock'); +// } + +/** + * Renders the client-side page. + * @param {PageContext} pageContext - The page context. + */ +async function onRenderClient(pageContext: PageContext): Promise { + const { Page }: { Page: any } = pageContext + const rootElement = document.getElementById('root') + if (rootElement != null) { + createRoot(rootElement).render( + + + + + + + + + + , + ) + } else { + console.error('No root element found') + } +} + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.unregister() + +export { onRenderClient } diff --git a/src/frontend/index.html b/src/frontend/src/renderer/+onRenderHtml.tsx similarity index 54% rename from src/frontend/index.html rename to src/frontend/src/renderer/+onRenderHtml.tsx index e4b78eae..39943840 100644 --- a/src/frontend/index.html +++ b/src/frontend/src/renderer/+onRenderHtml.tsx @@ -1,3 +1,12 @@ +// https://vike.dev/onRenderHtml +import { escapeInject } from 'vike/server' + +/** + * Renders the HTML template. + * @returns {Promise} The wrapped template. + */ +async function onRenderHtml(): Promise { + return escapeInject` @@ -8,6 +17,9 @@
- +` +} + +export { onRenderHtml } diff --git a/src/frontend/src/renderer/Link.tsx b/src/frontend/src/renderer/Link.tsx new file mode 100644 index 00000000..c696b756 --- /dev/null +++ b/src/frontend/src/renderer/Link.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import { usePageContext } from 'vike-react/usePageContext' + +export interface LinkProps { + children: React.ReactNode + className: string + href: string +} + +/** + * Link component. + * @param {LinkProps} props - The component props. + * @returns {React.JSX.Element} The rendered component. + */ +function Link(props: Readonly): React.JSX.Element { + const pageContext = usePageContext() + let pathname = window.location.pathname + + if (pageContext !== undefined) { + const { urlPathname } = pageContext + pathname = urlPathname + } + + const { href } = props + const isActive = href === '/' ? pathname === href : pathname.startsWith(href) + const className = [props.className, isActive && 'is-active'].filter(Boolean).join(' ') + return ( + + {props.children} + + ) +} + +export { Link } diff --git a/src/frontend/src/index.css b/src/frontend/src/renderer/PageLayout.css similarity index 87% rename from src/frontend/src/index.css rename to src/frontend/src/renderer/PageLayout.css index 6119ad9a..589b9bc7 100644 --- a/src/frontend/src/index.css +++ b/src/frontend/src/renderer/PageLayout.css @@ -1,3 +1,5 @@ +/* This CSS is common to all pages */ + :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -13,6 +15,13 @@ -moz-osx-font-smoothing: grayscale; } +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + a { font-weight: 500; color: #646cff; @@ -25,9 +34,7 @@ a:hover { body { margin: 0; display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; + justify-content: center; } h1 { diff --git a/src/frontend/src/renderer/PageLayout.tsx b/src/frontend/src/renderer/PageLayout.tsx new file mode 100644 index 00000000..87370d2b --- /dev/null +++ b/src/frontend/src/renderer/PageLayout.tsx @@ -0,0 +1,57 @@ +import React from 'react' + +import './PageLayout.css' + +/** + * PageLayout component. + * @param {object} props - The component props. + * @param {React.ReactNode} props.children - The children nodes. + * @returns {React.JSX.Element} The rendered component. + */ +function PageLayout({ children }: Readonly<{ children: React.ReactNode }>): React.JSX.Element { + return ( + + + Home + About + Blogs + + {children} + + ) +} + +/** + * Navigation component. + * @param {object} props - The component props. + * @param {React.ReactNode} props.children - The children nodes. + * @returns {React.JSX.Element} The rendered component. + */ +function Navigation({ children }: Readonly<{ children: React.ReactNode }>): React.JSX.Element { + return ( +
+ {children} +
+ ) +} + +/** + * Content component. + * @param {object} props - The component props. + * @param {React.ReactNode} props.children - The children nodes. + * @returns {React.JSX.Element} The rendered component. + */ +function Content({ children }: Readonly<{ children: React.ReactNode }>): React.JSX.Element { + return
{children}
+} + +export { PageLayout } diff --git a/src/frontend/ssl/cnf b/src/frontend/ssl/cnf new file mode 100644 index 00000000..03dd50f3 --- /dev/null +++ b/src/frontend/ssl/cnf @@ -0,0 +1,8 @@ +[dn] +CN=localhost +[req] +distinguished_name=dn +[EXT] +subjectAltName=DNS:localhost +keyUsage=digitalSignature +extendedKeyUsage=serverAuth diff --git a/src/frontend/ssl/localhost.crt b/src/frontend/ssl/localhost.crt new file mode 100644 index 00000000..e4d468e5 --- /dev/null +++ b/src/frontend/ssl/localhost.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8DCCAdigAwIBAgIUcg4qoVoFgWLI/pQSqWfrVilV6vwwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDYyODE4MTY1N1oXDTM0MDYy +NjE4MTY1N1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAuA57vEVV3nSVFrymj6kVqeA/7dsonwOMza3zsV6OXkqJ +WKAoEaD3POjMdkqM0odO18TVLfRob+HFzIoyVFWAhvW0VMOXpvTFZrdEgletyWvz +vL1VmHXqP9DPOqWUdFsjpCp0RCKkTDQgh2sdhsYfHCMQ+nX7ImuzDJuks4BQcJfF +e5zbR3gSEQ8ziU+KosBSycBrdu7i3fFD10BRmgdFOunkZxFez/W03qJHvn57gdkK +2J3ItOYFAVGyBBh4E2VuOebbFiZkAjtJMQsXprgvFJBlw66YvOoamGkan8kzaH+8 +b1hmxTHGACM7hIIaS8e5XyjAJXWzBUCQ5nqQAa9RqwIDAQABozowODAUBgNVHREE +DTALgglsb2NhbGhvc3QwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMB +MA0GCSqGSIb3DQEBCwUAA4IBAQAzerFsNimdN/tHF76eXO7/84yoWLANe3FnT83N +auahE17gBcjgO6GbTezhMNvkcGuZJFkwC61MeNj8ryCs8Cb0L2t5XctxWOSsImZi +vEaudFUK3Pd/LJHCPnsqn1nudIqjhMSac0CwKJyI13ngwxjSJuEuqqko/hYNZfGq +SAlDRBF2Tz8Kvl3MWxN+iK+6+zpJ8pC2mKKMmRlORZQ2JoKbsqsEJOSTTsQuMKPx +r0lXJYNMnwij6RcgXp5HG9/fUdIHjHreHk5FoJcmOMrTfwTs1kzN1PSWUJFZFwyO +UWBhRUnmbsJPGeHPlZGXt9pULwy6RSPcHCeja+KcxgMHPeKx +-----END CERTIFICATE----- diff --git a/src/frontend/ssl/localhost.key b/src/frontend/ssl/localhost.key new file mode 100644 index 00000000..ad5121d0 --- /dev/null +++ b/src/frontend/ssl/localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4Dnu8RVXedJUW +vKaPqRWp4D/t2yifA4zNrfOxXo5eSolYoCgRoPc86Mx2SozSh07XxNUt9Ghv4cXM +ijJUVYCG9bRUw5em9MVmt0SCV63Ja/O8vVWYdeo/0M86pZR0WyOkKnREIqRMNCCH +ax2Gxh8cIxD6dfsia7MMm6SzgFBwl8V7nNtHeBIRDzOJT4qiwFLJwGt27uLd8UPX +QFGaB0U66eRnEV7P9bTeoke+fnuB2QrYnci05gUBUbIEGHgTZW455tsWJmQCO0kx +CxemuC8UkGXDrpi86hqYaRqfyTNof7xvWGbFMcYAIzuEghpLx7lfKMAldbMFQJDm +epABr1GrAgMBAAECggEBAIh0HGIBGV86GUnpBKcfGPN/UIX748q37AyUeUW3L19S +bS7qVap0Jrfec68DKBHwxJAM2msedsrznBw/HH8PgKENyerJs0XQ1ASJvF3RuQLK +aMI1sB6+1LMJEImPNldpNixAWUAmWp4wSyl6TUKc4XWPvceh7lSfeffP8DQv3fMK +HrVRt9HjtDy79wN4I42oRw3AWJmhzJlWb+jAK16MieGnWBP8W2b0UmUbXUpQ20MC +lix8ojPzETCw0QLiMbIkSCZwtcZvF/EfrMbm3mwd33w4OtgQx5eRl+wiy9LlzyBM +ZkfchPQ0ioCBRgPg7owCSLl3fAAKpyVPLx5Z2WaQDzECgYEA71+jYGHyPqjb0nQY +pN9oS/xTlMVlfaYCRae7u4VaXC3KiUcYHR7RD5ylayHyfO/N+dZVZXp7BwOy+cZn +pLEJewhBWWqqmnfpOlkoNGZ+B/HId/aiKBHcX9Ql7dva7t4PbFG7tk4kXaRbAwCv +nG0oEeLucLeqtqSV1MlM/+EYBYkCgYEAxNc9T6bJ2hXvsj97Ell8vz7QpULEO2H5 +Uuyg+s7LZNkqKJreUehybFXpJLktYg2i98PmZ02h1zUmHbzD09ymg47WmIEnZgqR +S7uhi98dUXtEs40+hHzptBj/keCMTY+BL6nEDeJTFcoTwMHf1I3KAc5ZBS1BiPvQ +LbrNcvTeBJMCgYBnSfZeZYU5AnXwJsZnhjsj5ppOLKsxf4ulcM4yCUXHVr75Y2MF +VcHSIb7DLp/Kx1MyxgiNRD+H9FGrM7CPQREdNJ+2LK+2/Zz233fYvI0PcoYVNagc +8DAObaV8MI0U217+V3pPHQLWIVBgSFB+iB9tMGXA34/bRcOdUMtX8lICOQKBgQC/ +PT7b+/dwYo+WZgZ0NWz1gVnEtbFg4DcTUcK06eTB/hrviEcm3OcOSglRHHfzI7yJ +a1KWWt457/EwQw0e8Oj2N/hWAmT8xpeTNKAm/IXHfDOrHjb3EUUdLIxgdgDZ+epR +HGbV9mUybjnytGl6YKc6SfhDB0z8gWoog6zHWw+48QKBgQC/scXCbsdYi8kM+JNo +vnlqDyMgQNuRJFaWgjiLOCfAyhoJCKaWNzHY9vgb8KzQeBojtcfAL3nCYCQYbGtL +GytzUuS2M2RH+ZGq+U7LExciMbd0PcQEZrOx8neLt1bXj0FDv+3DuslutkYI5hJJ +0U0sg8gT22n5H4u0T8zDmOXh7w== +-----END PRIVATE KEY----- diff --git a/src/frontend/ssl/make.sh b/src/frontend/ssl/make.sh new file mode 100644 index 00000000..8397d23e --- /dev/null +++ b/src/frontend/ssl/make.sh @@ -0,0 +1,2 @@ +openssl req -x509 -out localhost.crt -keyout localhost.key -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -extensions EXT -config cnf -days 3650 || openssl req -x509 -out localhost.crt -keyout localhost.key -newkey rsa:2048 -nodes -sha256 -subj '//CN=localhost' -extensions EXT -config cnf -days 3650 +# openssl pkcs12 -export -name localhostServerCert -in localhost.crt -inkey localhost.key -out localhost.pfx diff --git a/src/frontend/tsconfig.json b/src/frontend/tsconfig.json index 24e049eb..31ea0423 100644 --- a/src/frontend/tsconfig.json +++ b/src/frontend/tsconfig.json @@ -6,6 +6,13 @@ "module": "ESNext", "skipLibCheck": true, + /* Paths */ + "baseUrl": "src", + "paths": { + "~/*": ["*"], + "~components/*": ["components/*"] + }, + /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index d3f1d1c2..0331e48e 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -1,8 +1,18 @@ import react from '@vitejs/plugin-react-swc' import { defineConfig } from 'vite' +import vike from 'vike/plugin' import mkcert from 'vite-plugin-mkcert' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react(), mkcert()], + server: { + port: 5173, + }, + plugins: [react(), vike({ prerender: true }), mkcert()], + resolve: { + alias: { + '~': '/src', + '~components': '/src/components', + }, + }, }) diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 5d12f6b2..9cc08b33 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -41,6 +41,40 @@ dependencies: "@types/json-schema" "^7.0.11" +"@babel/runtime@^7.12.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" + integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== + dependencies: + regenerator-runtime "^0.14.0" + +"@brillout/import@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@brillout/import/-/import-0.2.3.tgz#98f04656692b35d70664cc917f3cb0e8f74942dd" + integrity sha512-1T8WlD75eeFSMrptGy8jiLHmfHgMmSjWvLOIUvHmSVZt+6k0eQqYUoK4KbmE4T9pVLIfxvZSOm2D68VEqKRHRw== + +"@brillout/json-serializer@^0.5.1", "@brillout/json-serializer@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@brillout/json-serializer/-/json-serializer-0.5.10.tgz#6279cf8f3313d6619b2a4f9f8512bc16e6653d7b" + integrity sha512-3bh/MS5pudu3H9l3a0KAE1RBfy/L95JWAEo8b2mPBN3H98wzCHYzgjQb9xRl58y+Kc7FgkjApgCFJV+zR06P5Q== + +"@brillout/picocolors@^1.0.11", "@brillout/picocolors@^1.0.13": + version "1.0.13" + resolved "https://registry.yarnpkg.com/@brillout/picocolors/-/picocolors-1.0.13.tgz#c494efe999ba24419324c28063ce9fc3040d7053" + integrity sha512-LblvMKItHbvkaIMI+Awsk1EEjmReE8E8Mgjtj3Pdn/qBvwQ6e+ts5uEqG6iTrK6JWndcxrQgSe664KfoteN6fA== + +"@brillout/require-shim@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@brillout/require-shim/-/require-shim-0.1.2.tgz#a3a93e2f46608735d0363c7f38979fcd1bbfb2ad" + integrity sha512-3I4LRHnVZXoSAsEoni5mosq9l6eiJED58d9V954W4CIZ88AUfYBanWGBGbJG3NztaRTpFHEA6wB3Hn93BmmJdg== + +"@brillout/vite-plugin-server-entry@^0.4.5": + version "0.4.6" + resolved "https://registry.yarnpkg.com/@brillout/vite-plugin-server-entry/-/vite-plugin-server-entry-0.4.6.tgz#32f7d65b53a9114c86647d602ae793408db53f14" + integrity sha512-VmnbkEVNY9pGnr2ICu+5lFnT3Zz4oblWxKZ1D4kutkzljxDOOBld8oWQI1RVup7c5OiG7XOHFJYYZS38BAXiLw== + dependencies: + "@brillout/import" "^0.2.3" + "@bundled-es-modules/cookie@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164" @@ -1054,6 +1088,11 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.25" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" + integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ== + "@rollup/rollup-android-arm-eabi@4.17.2": version "4.17.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz#1a32112822660ee104c5dd3a7c595e26100d4c2d" @@ -1728,16 +1767,16 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn@^8.0.0, acorn@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" + integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== + acorn@^8.11.2: version "8.11.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== -acorn@^8.9.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" - integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== - ajv-draft-04@^1.0.0, ajv-draft-04@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" @@ -1963,7 +2002,12 @@ braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -cac@^6.7.14: +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +cac@^6.0.0, cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== @@ -2268,6 +2312,11 @@ deprecation@^2.0.0: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +devalue@^4.3.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/devalue/-/devalue-4.3.3.tgz#e35df3bdc49136837e77986f629b9fa6fef50726" + integrity sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -2393,6 +2442,11 @@ es-errors@^1.2.1, es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-module-lexer@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.3.tgz#25969419de9c0b1fbe54279789023e8a9a788412" + integrity sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg== + es-object-atoms@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" @@ -2430,7 +2484,7 @@ es6-promise@^3.2.1: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== -esbuild@^0.19.11: +esbuild@^0.19.0, esbuild@^0.19.11: version "0.19.12" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== @@ -2767,7 +2821,7 @@ fast-equals@^5.0.1: resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== -fast-glob@^3.2.9: +fast-glob@^3.0.0, fast-glob@^3.2.9: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -3299,6 +3353,11 @@ isarray@^2.0.5: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== +isbot-fast@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/isbot-fast/-/isbot-fast-1.2.0.tgz#ef0ef1d5db34eb60777250ae26fceb72b94153e2" + integrity sha512-twjuQzy2gKMDVfKGQyQqrx6Uy4opu/fiVUTTpdqtFsd7OQijIp5oXvb27n5EemYXaijh5fomndJt/SPRLsEdSg== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -3565,6 +3624,11 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mrmime@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -3963,6 +4027,23 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.2" +react-error-boundary@^4.0.12: + version "4.0.13" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.13.tgz#80386b7b27b1131c5fbb7368b8c0d983354c7947" + integrity sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ== + dependencies: + "@babel/runtime" "^7.12.5" + +react-streaming@^0.3.27, react-streaming@^0.3.33: + version "0.3.33" + resolved "https://registry.yarnpkg.com/react-streaming/-/react-streaming-0.3.33.tgz#50ca71889e32780ecbda491a7ba2ebee2043a1d3" + integrity sha512-Yb6ZgYRRMM4h7nA+vmW72wHJW8OyXg1TmSj9S+mmX144tOemfzAZ51cAz7NCWvkyHwI1o8KC8rpXSuGPajQ4Cw== + dependencies: + "@brillout/import" "^0.2.3" + "@brillout/json-serializer" "^0.5.1" + "@brillout/picocolors" "^1.0.11" + isbot-fast "1.2.0" + react@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" @@ -3982,6 +4063,11 @@ reftools@^1.1.9: resolved "https://registry.yarnpkg.com/reftools/-/reftools-1.1.9.tgz#e16e19f662ccd4648605312c06d34e5da3a2b77e" integrity sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" @@ -4228,6 +4314,15 @@ simple-eval@1.0.0: dependencies: jsep "^1.1.2" +sirv@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" + integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -4238,6 +4333,19 @@ source-map-js@^1.2.0: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== +source-map-support@^0.5.0: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + spdx-exceptions@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" @@ -4397,6 +4505,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -4573,6 +4686,40 @@ validator@^13.11.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== +vike-react-query@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/vike-react-query/-/vike-react-query-0.1.0.tgz#1f4a34a3567b47e29aa28ab4e142224a54b1a992" + integrity sha512-sXN9oIIeuixwj6A0ln5zzJ1CdKFWvygiKmezeyxxnqhrK4fV1zYUzu6NWrq8At90tH47M1nwYTZEt2lCn6o3Gg== + dependencies: + devalue "^4.3.2" + react-error-boundary "^4.0.12" + +vike-react@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/vike-react/-/vike-react-0.4.15.tgz#7db607e0feb03fa84a8daeb4ae668b70906e012c" + integrity sha512-uH6NtfE0/mHimE7Rp8qYY03NX8AnlI1cDQBTX6+Lsrp7nKQu7wAZ4R1/CyS/MC2/wGq6nYcRR6zzi/1QhZl1EA== + dependencies: + react-streaming "^0.3.27" + +vike@^0.4.177: + version "0.4.177" + resolved "https://registry.yarnpkg.com/vike/-/vike-0.4.177.tgz#f41a837d366322b5be0fbf7e5590a9a543cc47b5" + integrity sha512-ZCyJkeNJ+ssmkoVyrET1tDsKfW+y7Is3vwzkSDeac+disp8KITJWUMvgJsOPKII/q6eNZGbJWnZ+v3Xli0rong== + dependencies: + "@brillout/import" "^0.2.3" + "@brillout/json-serializer" "^0.5.10" + "@brillout/picocolors" "^1.0.13" + "@brillout/require-shim" "^0.1.2" + "@brillout/vite-plugin-server-entry" "^0.4.5" + acorn "^8.0.0" + cac "^6.0.0" + es-module-lexer "^1.0.0" + esbuild "^0.19.0" + fast-glob "^3.0.0" + semver "^7.6.2" + sirv "^2.0.0" + source-map-support "^0.5.0" + vite-plugin-mkcert@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/vite-plugin-mkcert/-/vite-plugin-mkcert-1.17.5.tgz#175f1a2a99c110fa87b2f2e6390b22656674a67b"