diff --git a/e2e/react-vite/houdini.config.js b/e2e/react-vite/houdini.config.js deleted file mode 100644 index 73097954b..000000000 --- a/e2e/react-vite/houdini.config.js +++ /dev/null @@ -1,36 +0,0 @@ -/// -/// - -/** @type {import('houdini').ConfigFile} */ -const config = { - schemaPath: '../_api/*.graphql', - defaultPartial: true, - scalars: { - DateTime: { - type: 'Date', - // turn the api's response into that type - unmarshal(val) { - return new Date(val) - }, - // turn the value into something the API can use - marshal(val) { - return val.getTime() - }, - }, - File: { - type: 'File', - }, - }, - - types: { - RentedBook: { - keys: ['userId', 'bookId'], - }, - }, - - plugins: { - 'houdini-react': {}, - }, -} - -export default config diff --git a/e2e/react-vite/index.html b/e2e/react-vite/index.html deleted file mode 100644 index 16685b9d2..000000000 --- a/e2e/react-vite/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Houdini • e2e • React vite - - -
- - - diff --git a/e2e/react-vite/package.json b/e2e/react-vite/package.json deleted file mode 100644 index 8c01bb424..000000000 --- a/e2e/react-vite/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "e2e-react-vite", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "build:": "cd ../../ && ((run build && cd -) || (cd - && exit 1))", - "build:dev": "pnpm build: && pnpm dev", - "build:test": "pnpm build: && pnpm test", - "build:build": "pnpm build: && pnpm build", - "web": "vite ", - "api": "cross-env TZ=utc e2e-api", - "dev": "concurrently \"pnpm run web\" \"pnpm run api\" -n \"web,api\" -c \"green,magenta\"", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "houdini": "workspace:^", - "houdini-react": "workspace:^", - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/react": "^18.0.27", - "@types/react-dom": "^18.0.10", - "@vitejs/plugin-react": "^3.1.0", - "concurrently": "7.1.0", - "cross-env": "^7.0.3", - "e2e-api": "workspace:^", - "typescript": "^4.9.3", - "vite": "^4.1.0" - } -} diff --git a/e2e/react-vite/public/vite.svg b/e2e/react-vite/public/vite.svg deleted file mode 100644 index e7b8dfb1b..000000000 --- a/e2e/react-vite/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/e2e/react-vite/src/App.css b/e2e/react-vite/src/App.css deleted file mode 100644 index df674c0d8..000000000 --- a/e2e/react-vite/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/e2e/react-vite/src/App.tsx b/e2e/react-vite/src/App.tsx deleted file mode 100644 index 850199333..000000000 --- a/e2e/react-vite/src/App.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useQuery, useFragment, graphql, HoudiniProvider, type UserInfo } from '$houdini' -import * as React from 'react' - -import client from './client' - -export default function App() { - return ( - - - - - - ) -} - -function Query() { - const [variables, setVariables] = React.useState({ id: '1' }) - const [pending, start] = React.useTransition() - - const data = useQuery( - graphql(` - query MyQuery($id: ID!) { - user(id: $id, snapshot: "react-vite-e2e") { - id - ...UserInfo - } - } - `), - variables - ) - - return ( - <> -
- - - {pending && 'pending'} -
- - - - ) -} - -function Fragment({ user }: { user: UserInfo }) { - const data = useFragment( - user, - graphql(` - fragment UserInfo on User { - id - name - } - `) - ) - - return ( -
- {data.id}: {data.name} -
- ) -} diff --git a/e2e/react-vite/src/assets/react.svg b/e2e/react-vite/src/assets/react.svg deleted file mode 100644 index 6c87de9bb..000000000 --- a/e2e/react-vite/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/e2e/react-vite/src/client.ts b/e2e/react-vite/src/client.ts deleted file mode 100644 index 066fdb2b2..000000000 --- a/e2e/react-vite/src/client.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HoudiniClient } from '$houdini' - -// Export the Houdini client -export default new HoudiniClient({ - url: 'http://localhost:4000/graphql', - plugins: [ - () => ({ - network(ctx, { next }) { - setTimeout(() => next(ctx), 500) - }, - }), - ], -}) diff --git a/e2e/react-vite/src/index.css b/e2e/react-vite/src/index.css deleted file mode 100644 index 7b9240bec..000000000 --- a/e2e/react-vite/src/index.css +++ /dev/null @@ -1,69 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/e2e/react-vite/src/main.tsx b/e2e/react-vite/src/main.tsx deleted file mode 100644 index 52607b195..000000000 --- a/e2e/react-vite/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' - -import App from './App' - -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - -) diff --git a/e2e/react-vite/src/vite-env.d.ts b/e2e/react-vite/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/e2e/react-vite/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/e2e/react-vite/tsconfig.json b/e2e/react-vite/tsconfig.json deleted file mode 100644 index b04ec87c5..000000000 --- a/e2e/react-vite/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "paths": { - "$houdini": ["./$houdini"], - "$houdini/*": ["./$houdini/*"] - } - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/e2e/react-vite/tsconfig.node.json b/e2e/react-vite/tsconfig.node.json deleted file mode 100644 index d3bf4b829..000000000 --- a/e2e/react-vite/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/e2e/react-vite/vite.config.ts b/e2e/react-vite/vite.config.ts deleted file mode 100644 index 3197a37f6..000000000 --- a/e2e/react-vite/vite.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import react from '@vitejs/plugin-react' -import { path } from 'houdini' -import houdini from 'houdini/vite' -import { defineConfig } from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [houdini(), react()], - // TODO: the vite plugin should do this - resolve: { - alias: { - $houdini: path.resolve('.', '/$houdini'), - '$houdini/*': path.resolve('.', '/$houdini', '*'), - }, - }, -}) diff --git a/e2e/react-vite/.gitignore b/e2e/react/.gitignore similarity index 100% rename from e2e/react-vite/.gitignore rename to e2e/react/.gitignore diff --git a/e2e/router/houdini.config.js b/e2e/react/houdini.config.js similarity index 84% rename from e2e/router/houdini.config.js rename to e2e/react/houdini.config.js index 5089a54eb..0bfb150b1 100644 --- a/e2e/router/houdini.config.js +++ b/e2e/react/houdini.config.js @@ -1,6 +1,5 @@ /// /// - /** @type {import('houdini').ConfigFile} */ const config = { schemaPath: '../_api/*.graphql', @@ -29,7 +28,12 @@ const config = { }, plugins: { - 'houdini-react': {}, + 'houdini-react': { + auth: { + redirect: '/auth/token', + sessionKeys: ['supersecret'], + }, + }, }, } diff --git a/e2e/router/package.json b/e2e/react/package.json similarity index 100% rename from e2e/router/package.json rename to e2e/react/package.json diff --git a/e2e/router/src/+client.js b/e2e/react/src/+client.js similarity index 100% rename from e2e/router/src/+client.js rename to e2e/react/src/+client.js diff --git a/e2e/router/src/+index.jsx b/e2e/react/src/+index.jsx similarity index 100% rename from e2e/router/src/+index.jsx rename to e2e/react/src/+index.jsx diff --git a/e2e/router/src/routes/+layout.gql b/e2e/react/src/routes/+layout.gql similarity index 100% rename from e2e/router/src/routes/+layout.gql rename to e2e/react/src/routes/+layout.gql diff --git a/e2e/router/src/routes/+layout.tsx b/e2e/react/src/routes/+layout.tsx similarity index 100% rename from e2e/router/src/routes/+layout.tsx rename to e2e/react/src/routes/+layout.tsx diff --git a/e2e/router/src/routes/+page.tsx b/e2e/react/src/routes/+page.tsx similarity index 100% rename from e2e/router/src/routes/+page.tsx rename to e2e/react/src/routes/+page.tsx diff --git a/e2e/router/src/routes/users/[id]/+page.gql b/e2e/react/src/routes/users/[id]/+page.gql similarity index 100% rename from e2e/router/src/routes/users/[id]/+page.gql rename to e2e/react/src/routes/users/[id]/+page.gql diff --git a/e2e/router/src/routes/users/[id]/+page.tsx b/e2e/react/src/routes/users/[id]/+page.tsx similarity index 100% rename from e2e/router/src/routes/users/[id]/+page.tsx rename to e2e/react/src/routes/users/[id]/+page.tsx diff --git a/e2e/router/tsconfig.json b/e2e/react/tsconfig.json similarity index 100% rename from e2e/router/tsconfig.json rename to e2e/react/tsconfig.json diff --git a/e2e/router/vite.config.ts b/e2e/react/vite.config.ts similarity index 100% rename from e2e/router/vite.config.ts rename to e2e/react/vite.config.ts diff --git a/e2e/router/.gitignore b/e2e/router/.gitignore deleted file mode 100644 index a547bf36d..000000000 --- a/e2e/router/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/packages/houdini-react/package.json b/packages/houdini-react/package.json index a7bf066a9..a2add908b 100644 --- a/packages/houdini-react/package.json +++ b/packages/houdini-react/package.json @@ -20,8 +20,11 @@ "typedefs": "scripts typedefs --plugin" }, "devDependencies": { + "@types/cookie-parser": "^1.4.3", + "@types/cookie-session": "^2.0.44", + "@types/cookies": "^0.7.7", "@types/estraverse": "^5.1.2", - "@types/next": "^9.0.0", + "@types/express": "^4.17.17", "@types/react-dom": "^18.0.10", "next": "^13.0.1", "scripts": "workspace:^" @@ -30,8 +33,11 @@ "@babel/parser": "^7.19.3", "@babel/types": "^7.21.4", "@types/react": "^18.0.28", - "@types/rollup": "^0.54.0", + "cookie-parser": "^1.4.6", + "cookie-session": "^2.0.0", + "cookies": "^0.8.0", "estraverse": "^5.3.0", + "express": "^4.18.2", "graphql": "^15.8.0", "houdini": "workspace:^", "react": "^18.2.0", @@ -49,10 +55,19 @@ "types": "./build/plugin/index.d.ts", "import": "./build/plugin-esm/index.js", "require": "./build/plugin-cjs/index.js" + }, + "./server": { + "types": "./build/server/index.d.ts", + "import": "./build/server-esm/index.js", + "require": "./build/server-cjs/index.js" } }, "typesVersions": { - "*": {} + "*": { + "server": [ + "build/server/index.d.ts" + ] + } }, "main": "./build/plugin-cjs/index.js", "types": "./build/plugin/index.d.ts" diff --git a/packages/houdini-react/src/plugin/codegen/render.test.ts b/packages/houdini-react/src/plugin/codegen/render.test.ts index 0cb05dadb..a63ed40c4 100644 --- a/packages/houdini-react/src/plugin/codegen/render.test.ts +++ b/packages/houdini-react/src/plugin/codegen/render.test.ts @@ -30,6 +30,7 @@ test('generates render functions', async function () { cache, loaded_queries, loaded_artifacts, + session, ...config } ) { @@ -38,6 +39,7 @@ test('generates render functions', async function () { cache={cache} {...router_cache()} loaded_queries={loaded_queries} + session={session} loaded_artifacts={loaded_artifacts} />, config); } `) diff --git a/packages/houdini-react/src/plugin/codegen/render.ts b/packages/houdini-react/src/plugin/codegen/render.ts index 40f3d9f2a..d1080dcb0 100644 --- a/packages/houdini-react/src/plugin/codegen/render.ts +++ b/packages/houdini-react/src/plugin/codegen/render.ts @@ -22,13 +22,14 @@ import { renderToStream } from 'react-streaming/server' import App from './App' import { router_cache } from '$houdini' -export function render_to_stream({url, cache, loaded_queries, loaded_artifacts, ...config}) { +export function render_to_stream({url, cache, loaded_queries, loaded_artifacts, session, ...config}) { return renderToStream( , config diff --git a/packages/houdini-react/src/plugin/config.ts b/packages/houdini-react/src/plugin/config.ts index 54a8d28ee..0fb5cacbe 100644 --- a/packages/houdini-react/src/plugin/config.ts +++ b/packages/houdini-react/src/plugin/config.ts @@ -5,13 +5,11 @@ import { testConfig } from 'houdini/test' import type { HoudiniReactPluginConfig } from '.' import { hooks } from '.' -export function plugin_config(config: Config): Required { +export function plugin_config(config: Config): HoudiniReactPluginConfig { return config.pluginConfig('houdini-react') } -export async function test_config( - extraConfig: Partial = {} -): Promise { - const config = testConfig(extraConfig) +export async function test_config(): Promise { + const config = testConfig() const plugin = await hooks() // @ts-ignore config.plugins.push({ diff --git a/packages/houdini-react/src/plugin/index.ts b/packages/houdini-react/src/plugin/index.ts index 393cbeec1..28468efd2 100644 --- a/packages/houdini-react/src/plugin/index.ts +++ b/packages/houdini-react/src/plugin/index.ts @@ -259,4 +259,18 @@ ${ export default plugin('houdini-react', hooks) -export type HoudiniReactPluginConfig = {} +export type HoudiniReactPluginConfig = { + auth?: HoudiniReactAuthStrategy +} + +type HoudiniReactAuthStrategy = + | { + redirect: string + sessionKeys: string[] + url: string + } + | { + mutation: string + sessionKeys: string[] + url: string + } diff --git a/packages/houdini-react/src/plugin/vite.tsx b/packages/houdini-react/src/plugin/vite.tsx index 08e0b8cad..389d8b476 100644 --- a/packages/houdini-react/src/plugin/vite.tsx +++ b/packages/houdini-react/src/plugin/vite.tsx @@ -1,9 +1,13 @@ import { PluginHooks, Config, Cache, path, QueryArtifact, fs } from 'houdini' import type { renderToStream as streamingRender } from 'react-streaming/server' -import type { ViteDevServer } from 'vite' +import type { Connect, ViteDevServer } from 'vite' import { RouterManifest } from '../runtime' import { find_match } from '../runtime/routing/lib/match' +import { configure_server } from '../server' +import { dev_server } from '../server/compat' +import { get_session } from '../server/session' +import { plugin_config } from './config' import { render_server_path } from './conventions' // in order to coordinate the client and server, the client's pending request cache @@ -91,7 +95,7 @@ export default { ) // hydrate the application for interactivity - hydrateRoot(document, ) + hydrateRoot(document, ) ` } @@ -116,70 +120,95 @@ if (window.__houdini__nav_caches__ && window.__houdini__nav_caches__.artifact_ca // render that we will use in production. This means that we need to // capture the request before vite's dev server processes it. configureServer(server) { - server.middlewares.use(async (request, response, next) => { - if (!request.url) { - return next() - } - - // pull in the project's manifest - const { default: manifest } = (await server.ssrLoadModule( - path.join( - server.houdiniConfig.pluginRuntimeDirectory('houdini-react'), - 'manifest.js' - ) - )) as { default: RouterManifest } - - // find the matching url - const [match] = find_match(manifest, request.url, true) - if (!match) { - return next() - } - - // get the function that we can call to render the response - // on the server - const { render_to_stream } = await load_render(server) - - // instanitate a cache we can use - const cache = new Cache({ disabled: false }) - - // in order to stream values to the client we need to track what we load - const loaded_queries: Record = {} - const loaded_artifacts: Record = {} - - // build up the pipe to render the response - const { pipe, injectToStream } = await render_to_stream({ - loaded_queries, - loaded_artifacts, - url: request.url, - cache, - userAgent: 'Vite', - }) - - // our pending cache needs to start with signals that we can alert - // for every query that we will send as part of the initial request - const pending_queries = Object.keys(match.documents) - const pending_query_names = pending_queries - .filter((q) => !(q in loaded_queries)) - .join(',') - - // start streaming the response to the user - pipe?.(response) - - // add the initial scripts to the page - injectToStream(` - - - - - - - `) + // wrap vite's server into the generic server interface + const houdini_server = dev_server({ + server: server.middlewares, + config: server.houdiniConfig, + }) + + // inject the necessary routes into vite's internal connect server + configure_server({ + server: houdini_server, + config: server.houdiniConfig, }) + + // any routes that aren't auth routes need to be rendered by the streaming handler + server.middlewares.use(render_stream(server)) }, } as PluginHooks['vite'] +const render_stream = + ( + server: ViteDevServer & { + houdiniConfig: Config + } + ): Connect.NextHandleFunction => + async (request, response, next) => { + if (!request.url) { + return next() + } + + // pull in the project's manifest + const { default: manifest } = (await server.ssrLoadModule( + path.join(server.houdiniConfig.pluginRuntimeDirectory('houdini-react'), 'manifest.js') + )) as { default: RouterManifest } + + // find the matching url + const [match] = find_match(manifest, request.url, true) + if (!match) { + return next() + } + + // load the session information + const config = plugin_config(server.houdiniConfig) + const session = get_session( + new Headers(request.headers as Record), + config.auth?.sessionKeys ?? [] + ) + + // get the function that we can call to render the response + // on the server + const { render_to_stream } = await load_render(server) + + // instanitate a cache we can use + const cache = new Cache({ disabled: false }) + + // in order to stream values to the client we need to track what we load + const loaded_queries: Record = {} + const loaded_artifacts: Record = {} + + // build up the pipe to render the response + const { pipe, injectToStream } = await render_to_stream({ + loaded_queries, + loaded_artifacts, + url: request.url, + cache, + session, + userAgent: 'Vite', + }) + + // our pending cache needs to start with signals that we can alert + // for every query that we will send as part of the initial request + const pending_queries = Object.keys(match.documents) + const pending_query_names = pending_queries.filter((q) => !(q in loaded_queries)).join(',') + + // start streaming the response to the user + pipe?.(response) + + // add the initial scripts to the page + injectToStream(` + + + + + + + `) + } + async function load_render(server: ViteDevServer & { houdiniConfig: Config }) { // load the function to rener the response from the generated output // this is a hack to avoid a dependency issue with pnpm (i think) @@ -192,6 +221,7 @@ async function load_render(server: ViteDevServer & { houdiniConfig: Config }) { loaded_artifacts: Record cache: Cache url: string + session: App.Session } & Parameters[1] ) => ReturnType } diff --git a/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts b/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts index c3d1b4f54..886ebec26 100644 --- a/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts +++ b/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts @@ -15,6 +15,8 @@ import type { } from '$houdini/runtime/lib/types' import React from 'react' +import { useSession } from '../routing/components/Router' + export function useDocumentHandle< _Artifact extends QueryArtifact, _Data extends GraphQLObject, @@ -31,6 +33,9 @@ export function useDocumentHandle< const [forwardPending, setForwardPending] = React.useState(false) const [backwardPending, setBackwardPending] = React.useState(false) + // grab the current session value + const session = useSession() + // @ts-expect-error: avoiding an as DocumentHandle<_Artifact, _Data, _Input> return React.useMemo>(() => { const wrapLoad = <_Result>( @@ -45,7 +50,12 @@ export function useDocumentHandle< } } - const fetchQuery: FetchFn<_Data, _Input> = (args) => observer.send(args) + // add the session value to the + const fetchQuery: FetchFn<_Data, _Input> = (args) => + observer.send({ + ...args, + session, + }) // only consider paginated queries if (artifact.kind !== ArtifactKind.Query || !artifact.refetch?.paginated) { @@ -56,9 +66,6 @@ export function useDocumentHandle< } } - // TODO: session - const getSession = async () => ({} as App.Session) - // if the artifact supports cursor pagination, then add the cursor handlers if (artifact.refetch.method === 'cursor') { const handlers = cursorHandlers<_Data, _Input>({ @@ -74,9 +81,10 @@ export function useDocumentHandle< applyUpdates: updates, ...args?.cacheParams, }, + session, }) }, - getSession, + getSession: async () => session, }) return { @@ -108,9 +116,7 @@ export function useDocumentHandle< }, }) }, - - // TODO: session - getSession: async () => ({} as App.Session), + getSession: async () => session, }) return { @@ -129,7 +135,7 @@ export function useDocumentHandle< refetch: fetchQuery, partial: storeValue.partial, } - }, [artifact, observer, storeValue, true, true]) + }, [artifact, observer, session, storeValue, true, true]) } export type DocumentHandle< diff --git a/packages/houdini-react/src/runtime/hooks/useDocumentSubscription.ts b/packages/houdini-react/src/runtime/hooks/useDocumentSubscription.ts index 0ad7e46db..68211d21a 100644 --- a/packages/houdini-react/src/runtime/hooks/useDocumentSubscription.ts +++ b/packages/houdini-react/src/runtime/hooks/useDocumentSubscription.ts @@ -2,6 +2,7 @@ import type { DocumentArtifact, GraphQLVariables, QueryResult } from '$houdini/l import type { DocumentStore, SendParams } from '$houdini/runtime/client' import type { GraphQLObject } from 'houdini' +import { useSession } from '../routing/components/Router' import useDeepCompareEffect from './useDeepCompareEffect' import { useDocumentStore, type UseDocumentStoreParams } from './useDocumentStore' @@ -29,13 +30,16 @@ export function useDocumentSubscription< ...observeParams, }) + // grab the current session value + const session = useSession() + // whenever the variables change, we need to retrigger the query useDeepCompareEffect(() => { if (!disabled) { observer.send({ variables, - // TODO: session/metadata - session: {}, + session, + // TODO: metadata metadata: {}, ...send, }) @@ -46,7 +50,7 @@ export function useDocumentSubscription< observer.cleanup() } } - }, [disabled, observer, variables ?? {}, send ?? {}]) + }, [disabled, session, observer, variables ?? {}, send ?? {}]) return [ { diff --git a/packages/houdini-react/src/runtime/hooks/useMutation.ts b/packages/houdini-react/src/runtime/hooks/useMutation.ts index 945e01e84..85dd9c256 100644 --- a/packages/houdini-react/src/runtime/hooks/useMutation.ts +++ b/packages/houdini-react/src/runtime/hooks/useMutation.ts @@ -5,6 +5,7 @@ import type { GraphQLVariables, } from '$houdini/runtime/lib/types' +import { useSession } from '../routing/components/Router' import { useDocumentStore } from './useDocumentStore' export type MutationHandler<_Result, _Input, _Optimistic extends GraphQLObject> = (args: { @@ -30,6 +31,9 @@ export function useMutation< // grab the pending state from the document store const pending = storeValue.fetching + // grab the current session value + const session = useSession() + // sending the mutation just means invoking the observer's send method const mutate: MutationHandler<_Result, _Input, _Optimistic> = ({ metadata, @@ -40,8 +44,7 @@ export function useMutation< observer.send({ variables, metadata, - // TODO: session/metadata - session: {}, + session, stuff: { ...mutationConfig, }, diff --git a/packages/houdini-react/src/runtime/index.tsx b/packages/houdini-react/src/runtime/index.tsx index 8bd9b39c4..36b34d49c 100644 --- a/packages/houdini-react/src/runtime/index.tsx +++ b/packages/houdini-react/src/runtime/index.tsx @@ -23,11 +23,13 @@ export function Router({ last_variables, loaded_queries, loaded_artifacts, + session, }: { intialURL: string cache: Cache loaded_queries?: Record loaded_artifacts?: Record + session?: App.Session } & RouterCache) { return ( { // track the new variables @@ -157,6 +160,7 @@ function useLoadPage({ .send({ variables: variables, cacheParams: { disableSubscriptions: true }, + session, }) .then(() => { data_cache.set(id, observer) @@ -302,6 +306,7 @@ export function RouterContextProvider({ data_cache, pending_cache, last_variables, + session: ssrSession = {}, }: { children: React.ReactElement client: HoudiniClient @@ -311,7 +316,28 @@ export function RouterContextProvider({ data_cache: SuspenseCache> pending_cache: PendingCache last_variables: LRUCache + session?: App.Session }) { + // the session is top level state + // on the server, we can just use + const [session, setSession] = React.useState(ssrSession) + + // if we detect an event that contains a new session value + const handleNewSession = React.useCallback((event: CustomEvent) => { + setSession(event.detail) + }, []) + + React.useEffect(() => { + // @ts-ignore + window.addEventListener('_houdini_session_', handleNewSession) + + // cleanup this component + return () => { + // @ts-ignore + window.removeEventListener('_houdini_session_', handleNewSession) + } + }, []) + return ( {children} @@ -349,6 +376,9 @@ type RouterContext = { // A way to track the last known good variables last_variables: LRUCache + + // The current session + session: App.Session } export type PendingCache = SuspenseCache< @@ -374,6 +404,19 @@ export function useCache() { return useRouterContext().cache } +export function updateLocalSession(session: App.Session) { + window.dispatchEvent( + new CustomEvent('_houdini_session_', { + bubbles: true, + detail: session, + }) + ) +} + +export function useSession() { + return useRouterContext().session +} + export function useCurrentVariables(): GraphQLVariables { return React.useContext(VariableContext) } diff --git a/packages/houdini-react/src/runtime/routing/components/index.ts b/packages/houdini-react/src/runtime/routing/components/index.ts index 1248cc42e..28c8082d7 100644 --- a/packages/houdini-react/src/runtime/routing/components/index.ts +++ b/packages/houdini-react/src/runtime/routing/components/index.ts @@ -1,2 +1,2 @@ export { Link } from './Link' -export { Router, RouterContextProvider, useClient } from './Router' +export { Router, RouterContextProvider, useClient, updateLocalSession } from './Router' diff --git a/packages/houdini-react/src/server/compat.ts b/packages/houdini-react/src/server/compat.ts new file mode 100644 index 000000000..b4e1b609e --- /dev/null +++ b/packages/houdini-react/src/server/compat.ts @@ -0,0 +1,36 @@ +// this file defines the compatibility layer between the vite dev server and houdini's +// server infrastrcture +import type { Config } from 'houdini' +import type { Connect } from 'vite' + +import type { Server, ServerMiddleware } from '.' + +// wrap vite's dev server in something our handlers can integrate with +export function dev_server({ server, config }: { server: Connect.Server; config: Config }): Server { + return { + use(fn: ServerMiddleware) { + server.use((req, res, next) => { + fn( + { + url: req.url, + headers: new Headers(req.headers as Record), + }, + { + ...res, + redirect(url: string, status: number = 307) { + // Respond with a redirect + res.statusCode = status + res.setHeader('location', url) + res.setHeader('content-length', '0') + + // dont call next + return res.end() + }, + set_header: res.setHeader.bind(res), + }, + next + ) + }) + }, + } +} diff --git a/packages/houdini-react/src/server/index.ts b/packages/houdini-react/src/server/index.ts new file mode 100644 index 000000000..334455621 --- /dev/null +++ b/packages/houdini-react/src/server/index.ts @@ -0,0 +1,69 @@ +// This function defines the primary entrypoint for requests +import type { Config } from 'houdini' + +import { plugin_config as get_plugin_config } from '../plugin/config' +import { set_session } from './session' + +export function configure_server({ server, config }: { server: Server; config: Config }) { + server.use(server_handler({ config })) +} + +function server_handler({ config }: { config: Config }): ServerMiddleware { + // load the plugin config + const plugin_config = get_plugin_config(config) + + return (req, res, next) => { + // only consider requests with valid urls + if (!req.url) { + next() + return + } + + // if the project is configured to authorize users by redirect then + // we might need to set the session value + if ( + plugin_config.auth && + 'redirect' in plugin_config.auth && + req.url.startsWith(plugin_config.auth.redirect) + ) { + return redirect_auth(req, res, next) + } + + // if we got this far, its not an auth request + next() + } +} + +const redirect_auth: ServerMiddleware = (req, res, next) => { + // the session and configuration are passed as query parameters in + // the url + const { searchParams } = new URL(req.url!, `http://${req.headers.get('host')}`) + const { redirectTo, ...session } = Object.fromEntries(searchParams.entries()) + + // encode the session information as a cookie in the response + set_session(res, session) + + // if there is a url to redirect to, do it + if (redirectTo) { + return res.redirect(redirectTo) + } + + // if we got this far we need to move onto the next middleware + next() +} + +export type Server = { + use(fn: ServerMiddleware): void +} + +export type ServerMiddleware = (req: IncomingRequest, res: ServerResponse, next: () => void) => void + +export type IncomingRequest = { + url?: string + headers: Headers +} + +export type ServerResponse = { + redirect(url: string, status?: number): void + set_header(name: string, value: string): void +} diff --git a/packages/houdini-react/src/server/session.ts b/packages/houdini-react/src/server/session.ts new file mode 100644 index 000000000..22cb18099 --- /dev/null +++ b/packages/houdini-react/src/server/session.ts @@ -0,0 +1,36 @@ +import cookieParser from 'cookie-parser' + +import type { ServerResponse } from '.' + +const session_cookie_name = '__houdini__' + +export function set_session(res: ServerResponse, value: App.Session) { + const today = new Date() + const expires = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000) // Add 7 days in milliseconds + + // serialize the value + const serialized = JSON.stringify(value) + + // set the cookie with a header + res.set_header( + 'Set-Cookie', + `${session_cookie_name}=${serialized}; Path=/; HttpOnly; Secure; SameSite=Lax; Expires=${expires.toUTCString()} ` + ) +} + +export function get_session(req: Headers, secrets: string[]): App.Session { + // get the cookie header + const cookie = req.get('cookie') + if (!cookie) { + return {} + } + + // parse the cookie header + const parsed = cookieParser.signedCookie(cookie, secrets) + if (!parsed) { + return {} + } + + // the value is an object with session information + return JSON.parse(parsed.split('=')[1]) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d08d40f6e..2b1e66b2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + importers: .: @@ -166,6 +170,49 @@ importers: specifier: ^0.0.6 version: 0.0.6 + e2e/react: + dependencies: + houdini: + specifier: workspace:^ + version: link:../../packages/houdini + houdini-react: + specifier: workspace:^ + version: link:../../packages/houdini-react + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-streaming: + specifier: ^0.3.10 + version: 0.3.10(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@types/react': + specifier: ^18.0.27 + version: 18.0.33 + '@types/react-dom': + specifier: ^18.0.10 + version: 18.0.11 + '@vitejs/plugin-react': + specifier: ^3.1.0 + version: 3.1.0(vite@4.1.4) + concurrently: + specifier: 7.1.0 + version: 7.1.0 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + e2e-api: + specifier: workspace:^ + version: link:../_api + typescript: + specifier: ^4.9.3 + version: 4.9.4 + vite: + specifier: ^4.1.0 + version: 4.1.4(@types/node@18.11.15) + e2e/react-vite: dependencies: houdini: @@ -460,12 +507,21 @@ importers: '@types/react': specifier: ^18.0.28 version: 18.0.33 - '@types/rollup': - specifier: ^0.54.0 - version: 0.54.0 + cookie-parser: + specifier: ^1.4.6 + version: 1.4.6 + cookie-session: + specifier: ^2.0.0 + version: 2.0.0 + cookies: + specifier: ^0.8.0 + version: 0.8.0 estraverse: specifier: ^5.3.0 version: 5.3.0 + express: + specifier: ^4.18.2 + version: 4.18.2 graphql: specifier: ^15.8.0 version: 15.8.0 @@ -488,12 +544,21 @@ importers: specifier: ^1.8.1 version: 1.8.1(react@18.2.0) devDependencies: + '@types/cookie-parser': + specifier: ^1.4.3 + version: 1.4.3 + '@types/cookie-session': + specifier: ^2.0.44 + version: 2.0.44 + '@types/cookies': + specifier: ^0.7.7 + version: 0.7.7 '@types/estraverse': specifier: ^5.1.2 version: 5.1.2 - '@types/next': - specifier: ^9.0.0 - version: 9.0.0(@babel/core@7.20.7)(react-dom@18.2.0)(react@18.2.0) + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 '@types/react-dom': specifier: ^18.0.10 version: 18.0.11 @@ -736,10 +801,10 @@ packages: '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-module-transforms': 7.21.2 '@babel/helpers': 7.21.0 - '@babel/parser': 7.21.4 + '@babel/parser': 7.21.8 '@babel/template': 7.20.7 '@babel/traverse': 7.21.4 - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 convert-source-map: 1.9.0 debug: 4.3.4(supports-color@9.3.1) gensync: 1.0.0-beta.2 @@ -770,7 +835,7 @@ packages: resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 @@ -824,19 +889,19 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.20.7 - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/helper-module-transforms@7.21.2: resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} @@ -849,7 +914,7 @@ packages: '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.20.7 '@babel/traverse': 7.21.4 - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 transitivePeerDependencies: - supports-color @@ -861,13 +926,13 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/helper-string-parser@7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} @@ -876,7 +941,6 @@ packages: /@babel/helper-string-parser@7.21.5: resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} @@ -892,7 +956,7 @@ packages: dependencies: '@babel/template': 7.20.7 '@babel/traverse': 7.21.4 - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 transitivePeerDependencies: - supports-color @@ -924,7 +988,7 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/parser@7.21.8: resolution: {integrity: sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==} @@ -932,7 +996,6 @@ packages: hasBin: true dependencies: '@babel/types': 7.21.5 - dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.20.7): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} @@ -1094,8 +1157,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.21.4 - '@babel/parser': 7.21.4 - '@babel/types': 7.21.4 + '@babel/parser': 7.21.8 + '@babel/types': 7.21.5 /@babel/traverse@7.17.3: resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} @@ -1143,8 +1206,8 @@ packages: '@babel/helper-function-name': 7.21.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.21.4 - '@babel/types': 7.21.4 + '@babel/parser': 7.21.8 + '@babel/types': 7.21.5 debug: 4.3.4(supports-color@9.3.1) globals: 11.12.0 transitivePeerDependencies: @@ -1182,7 +1245,6 @@ packages: '@babel/helper-string-parser': 7.21.5 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - dev: true /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -1679,7 +1741,7 @@ packages: ajv: 6.12.6 debug: 4.3.4(supports-color@9.3.1) espree: 9.4.1 - globals: 13.19.0 + globals: 13.20.0 ignore: 5.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -2391,6 +2453,13 @@ packages: '@babel/types': 7.21.4 dev: false + /@types/body-parser@1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 18.11.15 + dev: true + /@types/braces@3.0.1: resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==} dev: false @@ -2405,9 +2474,37 @@ packages: resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} dev: true + /@types/connect@3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 18.11.15 + dev: true + + /@types/cookie-parser@1.4.3: + resolution: {integrity: sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==} + dependencies: + '@types/express': 4.17.17 + dev: true + + /@types/cookie-session@2.0.44: + resolution: {integrity: sha512-3DheOZ41pql6raSIkqEPphJdhA2dX2bkS+s2Qacv8YMKkoCbAIEXbsDil7351ARzMqvfyDUGNeHGiRZveIzhqQ==} + dependencies: + '@types/express': 4.17.17 + '@types/keygrip': 1.0.2 + dev: true + /@types/cookie@0.5.1: resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} + /@types/cookies@0.7.7: + resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==} + dependencies: + '@types/connect': 3.4.35 + '@types/express': 4.17.17 + '@types/keygrip': 1.0.2 + '@types/node': 18.11.15 + dev: true + /@types/debug@4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: @@ -2429,6 +2526,24 @@ packages: /@types/estree@1.0.0: resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} + /@types/express-serve-static-core@4.17.35: + resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} + dependencies: + '@types/node': 18.11.15 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + '@types/send': 0.17.1 + dev: true + + /@types/express@4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.35 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.2 + dev: true + /@types/fs-extra@9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: @@ -2453,6 +2568,10 @@ packages: dependencies: '@types/unist': 2.0.6 + /@types/http-errors@2.0.1: + resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==} + dev: true + /@types/is-ci@3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -2482,6 +2601,10 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/keygrip@1.0.2: + resolution: {integrity: sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==} + dev: true + /@types/mdast@3.0.10: resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} dependencies: @@ -2494,6 +2617,14 @@ packages: '@types/braces': 3.0.1 dev: false + /@types/mime@1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + + /@types/mime@3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + dev: true + /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: true @@ -2506,21 +2637,6 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/next@9.0.0(@babel/core@7.20.7)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-gnBXM8rP1mnCgT1uE2z8SnpFTKRWReJlhbZLZkOLq/CH1ifvTNwjIVtXvsywTy1dwVklf+y/MB0Eh6FOa94yrg==} - deprecated: This is a stub types definition. next provides its own type definitions, so you do not need this installed. - dependencies: - next: 13.1.1(@babel/core@7.20.7)(react-dom@18.2.0)(react@18.2.0) - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - fibers - - node-sass - - react - - react-dom - - sass - dev: true - /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true @@ -2553,6 +2669,14 @@ packages: /@types/pug@2.0.6: resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} + /@types/qs@6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true + + /@types/range-parser@1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + /@types/react-dom@18.0.11: resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==} dependencies: @@ -2574,13 +2698,6 @@ packages: csstype: 3.1.1 dev: true - /@types/rollup@0.54.0: - resolution: {integrity: sha512-oeYztLHhQ98jnr+u2cs1c3tHOGtpzrm9DJlIdEjznwoXWidUbrI+X6ib7zCkPIbB7eJ7VbbKNQ5n/bPnSg6Naw==} - deprecated: This is a stub types definition for rollup (https://github.com/rollup/rollup). rollup provides its own type definitions, so you don't need @types/rollup installed! - dependencies: - rollup: 3.14.0 - dev: false - /@types/sass@1.43.1: resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} dependencies: @@ -2597,6 +2714,21 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true + /@types/send@0.17.1: + resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 18.11.15 + dev: true + + /@types/serve-static@1.15.2: + resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==} + dependencies: + '@types/http-errors': 2.0.1 + '@types/mime': 3.0.1 + '@types/node': 18.11.15 + dev: true + /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: false @@ -3098,6 +3230,14 @@ packages: event-target-shim: 5.0.1 dev: false + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + /acorn-jsx@5.3.2(acorn@8.8.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3220,6 +3360,10 @@ packages: deep-equal: 2.2.0 dev: true + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + dev: false + /array-includes@3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} @@ -3377,6 +3521,26 @@ packages: engines: {node: '>=8'} dev: true + /body-parser@1.20.1: + resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: false @@ -3444,6 +3608,11 @@ packages: dependencies: streamsearch: 1.1.0 + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: false + /c8@7.12.0: resolution: {integrity: sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==} engines: {node: '>=10.12.0'} @@ -3721,6 +3890,18 @@ packages: yargs: 16.2.0 dev: true + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: false + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -3728,10 +3909,47 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: false + /cookie-parser@1.4.6: + resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==} + engines: {node: '>= 0.8.0'} + dependencies: + cookie: 0.4.1 + cookie-signature: 1.0.6 + dev: false + + /cookie-session@2.0.0: + resolution: {integrity: sha512-hKvgoThbw00zQOleSlUr2qpvuNweoqBtxrmx0UFosx6AGi9lYtLoA+RbsvknrEX8Pr6MDbdWAb2j6SnMn+lPsg==} + engines: {node: '>= 0.10'} + dependencies: + cookies: 0.8.0 + debug: 3.2.7 + on-headers: 1.0.2 + safe-buffer: 5.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + dev: false + + /cookie@0.4.1: + resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==} + engines: {node: '>= 0.6'} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} + /cookies@0.8.0: + resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + keygrip: 1.1.0 + dev: false + /core-js@3.26.1: resolution: {integrity: sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==} requiresBuild: true @@ -4140,7 +4358,6 @@ packages: optional: true dependencies: ms: 2.0.0 - dev: true /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -4151,7 +4368,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /debug@4.3.4(supports-color@9.3.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -4255,10 +4471,20 @@ packages: robust-predicates: 3.0.1 dev: true + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -4342,6 +4568,10 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + /electron-to-chromium@1.4.284: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} @@ -4357,6 +4587,11 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + /enhanced-resolve@5.12.0: resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==} engines: {node: '>=10.13.0'} @@ -4711,6 +4946,10 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -5400,6 +5639,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: false + /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -5446,6 +5690,45 @@ packages: jest-util: 29.4.1 dev: false + /express@4.18.2: + resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -5547,6 +5830,21 @@ packages: engines: {node: '>=14.16'} dev: false + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -5626,6 +5924,16 @@ packages: fetch-blob: 3.2.0 dev: false + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: false + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -5960,6 +6268,17 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + /https-proxy-agent@2.2.4: resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==} engines: {node: '>= 4.5.0'} @@ -5995,7 +6314,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: true /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -6057,6 +6375,11 @@ packages: engines: {node: '>=12'} dev: true + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: false + /is-alphabetical@1.0.4: resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} dev: true @@ -6357,7 +6680,7 @@ packages: engines: {node: '>=8'} dependencies: '@babel/core': 7.21.4 - '@babel/parser': 7.21.4 + '@babel/parser': 7.21.8 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -6605,6 +6928,13 @@ packages: object.assign: 4.1.4 dev: true + /keygrip@1.1.0: + resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} + engines: {node: '>= 0.6'} + dependencies: + tsscmp: 1.0.6 + dev: false + /khroma@2.0.0: resolution: {integrity: sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==} dev: true @@ -6951,6 +7281,11 @@ packages: vfile-message: 2.0.4 dev: false + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + /memfs@3.4.12: resolution: {integrity: sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==} engines: {node: '>= 4.0.0'} @@ -6975,6 +7310,10 @@ packages: yargs-parser: 18.1.3 dev: true + /merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + dev: false + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7021,6 +7360,11 @@ packages: - react-dom dev: true + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: false + /micromark-core-commonmark@1.0.6: resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==} dependencies: @@ -7296,6 +7640,24 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: false + /mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} @@ -7375,21 +7737,24 @@ packages: /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + /nanoid@3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: true /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -7398,6 +7763,11 @@ packages: /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: false + /next@13.1.1(@babel/core@7.20.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==} engines: {node: '>=14.6.0'} @@ -7552,7 +7922,6 @@ packages: /object-inspect@1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} - dev: true /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} @@ -7609,6 +7978,18 @@ packages: es-abstract: 1.20.5 dev: true + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -7759,6 +8140,11 @@ packages: resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==} dev: false + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -7779,6 +8165,10 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + dev: false + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -7857,7 +8247,7 @@ packages: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.4 + nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 @@ -7957,6 +8347,14 @@ packages: react-is: 16.13.1 dev: true + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true @@ -8001,6 +8399,13 @@ packages: engines: {node: '>=6.0.0'} dev: false + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + /query-string@6.0.0: resolution: {integrity: sha512-QKgEnEoiigFPShVqMFp91YPaYGSaR4j3VIMVl+yKEm8jSgZzOuoFvY4s5mQxHAA/j5pexab5DtZv6W+JpQfjhw==} engines: {node: '>=6'} @@ -8027,6 +8432,21 @@ packages: engines: {node: '>=8'} dev: true + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: false + + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: false + /react-dom@16.14.0(react@16.14.0): resolution: {integrity: sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==} peerDependencies: @@ -8392,6 +8812,10 @@ packages: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: @@ -8412,7 +8836,6 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true /sander@0.5.1: resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} @@ -8450,6 +8873,39 @@ packages: dependencies: lru-cache: 6.0.0 + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -8457,6 +8913,10 @@ packages: /set-cookie-parser@2.5.1: resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -8485,7 +8945,6 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.1.3 object-inspect: 1.12.2 - dev: true /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -8639,6 +9098,11 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + /std-env@3.3.1: resolution: {integrity: sha512-3H20QlwQsSm2OvAxWIYhs+j01MzzqwMwGiiO1NQaJYZgJZFPuAbf95/DiKRBSTYIJ2FeGUc+B/6mPGcWP9dO3Q==} dev: true @@ -9097,6 +9561,11 @@ packages: dependencies: is-number: 7.0.0 + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + /totalist@3.0.0: resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} engines: {node: '>=6'} @@ -9145,6 +9614,11 @@ packages: /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + /tsscmp@1.0.6: + resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} + engines: {node: '>=0.6.x'} + dev: false + /tsutils@3.21.0(typescript@4.9.4): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -9267,6 +9741,14 @@ packages: engines: {node: '>=8'} dev: true + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true @@ -9365,6 +9847,11 @@ packages: engines: {node: '>= 10.0.0'} dev: false + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + /update-browserslist-db@1.0.10(browserslist@4.21.4): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true @@ -9411,6 +9898,11 @@ packages: is-typed-array: 1.1.10 which-typed-array: 1.1.9 + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + dev: false + /uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true @@ -9460,6 +9952,11 @@ packages: engines: {node: '>=12'} dev: false + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + /vfile-location@4.0.1: resolution: {integrity: sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==} dependencies: