diff --git a/.gitignore b/.gitignore
index 9a5aced..ca61cb5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,3 +137,4 @@ dist
# Vite logs files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
+.webssr/
diff --git a/README.md b/README.md
index d33609e..f1444a8 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,87 @@
# WebSSR
-SSR framework for Web components standard, which is based on WebCell design & infrastructure.
+
+SSR framework for Web components standard, which is based on WebCell design & infrastructure.
+
+## Overview
+
+WebSSR is a lightweight **server-side rendering framework** for the [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) standard. It renders pages using JSX on the server via [DOM-Renderer](https://github.com/EasyWebApp/DOM-Renderer) and serialises shadow roots with the [Declarative Shadow DOM](https://developer.chrome.com/docs/css-ui/declarative-shadow-dom) standard so browsers can hydrate without JavaScript.
+
+## Requirements
+
+- **Node.js ≥ 22**
+
+## Architecture
+
+| Concern | Technology |
+|---------|------------|
+| HTTP server | [Koa](https://koajs.com/) |
+| JSX → HTML streaming | [DOM-Renderer](https://github.com/EasyWebApp/DOM-Renderer) |
+| HTML serialisation / hydration | [Declarative Shadow DOM](https://github.com/EasyWebApp/declarative-shadow-dom-polyfill) |
+| File-based routing | Next.js App Router convention (`app/**/page.tsx`) |
+| Client component bundling | Parcel 2 (custom transformer plugin) |
+
+## Getting Started
+
+```bash
+npm install
+npm start # production
+npm run dev # development (auto-restarts on file changes)
+```
+
+The server listens on port **3000** by default. Override with the `PORT` environment variable.
+
+## File-Based Routing
+
+Pages live under the `app/` directory and follow the Next.js App Router naming convention:
+
+```
+app/
+ page.tsx → GET /
+ about/
+ page.tsx → GET /about
+ users/
+ [id]/
+ page.tsx → GET /users/:id
+```
+
+Each `page.tsx` must export an **async default function** that returns JSX:
+
+```tsx
+// app/page.tsx
+import type { PageProps } from '../source/types.js';
+
+export default async function HomePage({ params, searchParams }: PageProps) {
+ return
Hello, {searchParams.name ?? 'World'}! ;
+}
+```
+
+## Client Components
+
+Mark a module as a *client component* using the import attribute `with { runtime: 'client' }`:
+
+```tsx
+import { MyButton } from './MyButton' with { runtime: 'client' };
+```
+
+The **Parcel 2 transformer plugin** (`source/parcel-plugin/index.ts`) intercepts these imports:
+
+- **Server build** – replaces the import with a lightweight stub object so that the SSR renderer can emit the right custom-element tag without executing browser-only code.
+- **Client build** – leaves the import unchanged so Parcel bundles the real component code for the browser.
+
+## Project Structure
+
+```
+source/
+ server.ts Koa HTTP server entry point
+ router.ts File-based routing (scans app/**/page.tsx)
+ renderer.ts JSX → HTML via DOMRenderer (static + streaming)
+ polyfill.ts happy-dom DOM environment setup for SSR
+ types.ts Shared TypeScript types (PageProps, PageComponent)
+ parcel-plugin/
+ index.ts Parcel 2 Transformer for client component boundaries
+
+app/
+ page.tsx Example home page (GET /)
+ about/
+ page.tsx Example about page (GET /about)
+```
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..69494e7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "web-ssr",
+ "version": "0.1.0",
+ "description": "SSR framework for Web Components based on Declarative Shadow DOM",
+ "keywords": [
+ "web-components",
+ "ssr",
+ "server-side-rendering",
+ "declarative-shadow-dom",
+ "koa",
+ "jsx"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "packageManager": "pnpm@10.33.0",
+ "type": "module",
+ "engines": {
+ "node": ">=22"
+ },
+ "bin": {
+ "webssr": "./dist/cli.js"
+ },
+ "exports": {
+ ".": "./dist/index.js",
+ "./parcel-plugin": "./dist/parcel-plugin/index.js"
+ },
+ "scripts": {
+ "start": "node --import tsx/esm --import ./source/polyfill.ts source/server.ts",
+ "dev": "node --watch --import tsx/esm --import ./source/polyfill.ts source/server.ts",
+ "build": "tsc",
+ "test": "node --import tsx/esm --import ./source/polyfill.ts --test 'test/**/*.test.ts' 'test/**/*.test.tsx'"
+ },
+ "dependencies": {
+ "@koa/router": "^15.4.0",
+ "@parcel/core": "^2.16.4",
+ "commander-jsx": "^0.7.3",
+ "dom-renderer": "^2.6.4",
+ "happy-dom": "^20.8.9",
+ "koa": "^3.2.0",
+ "koa-static": "^5.0.0"
+ },
+ "overrides": {
+ "happy-dom": "^20.8.9"
+ },
+ "devDependencies": {
+ "@parcel/plugin": "^2.16.4",
+ "@types/koa": "^3.0.2",
+ "@types/koa-static": "^4.0.4",
+ "@types/node": "^22.0.0",
+ "tsx": "^4.19.3",
+ "typescript": "^5.8.3"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..92ad201
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,2215 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@koa/router':
+ specifier: ^15.4.0
+ version: 15.4.0(koa@3.2.0)
+ '@parcel/core':
+ specifier: ^2.16.4
+ version: 2.16.4(@swc/helpers@0.5.21)
+ commander-jsx:
+ specifier: ^0.7.3
+ version: 0.7.3(element-internals-polyfill@3.0.2)(typescript@5.9.3)
+ dom-renderer:
+ specifier: ^2.6.4
+ version: 2.6.4(element-internals-polyfill@3.0.2)(happy-dom@20.8.9)(typescript@5.9.3)
+ happy-dom:
+ specifier: ^20.8.9
+ version: 20.8.9
+ koa:
+ specifier: ^3.2.0
+ version: 3.2.0
+ koa-static:
+ specifier: ^5.0.0
+ version: 5.0.0
+ devDependencies:
+ '@parcel/plugin':
+ specifier: ^2.16.4
+ version: 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@types/koa':
+ specifier: ^3.0.2
+ version: 3.0.2
+ '@types/koa-static':
+ specifier: ^4.0.4
+ version: 4.0.4
+ '@types/node':
+ specifier: ^22.0.0
+ version: 22.19.17
+ tsx:
+ specifier: ^4.19.3
+ version: 4.21.0
+ typescript:
+ specifier: ^5.8.3
+ version: 5.9.3
+
+packages:
+
+ '@esbuild/aix-ppc64@0.27.7':
+ resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.27.7':
+ resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.27.7':
+ resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.27.7':
+ resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.27.7':
+ resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.27.7':
+ resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.27.7':
+ resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.27.7':
+ resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.27.7':
+ resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.27.7':
+ resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.27.7':
+ resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.27.7':
+ resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.27.7':
+ resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.27.7':
+ resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.27.7':
+ resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.27.7':
+ resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.27.7':
+ resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.27.7':
+ resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.27.7':
+ resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.27.7':
+ resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.27.7':
+ resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.27.7':
+ resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.27.7':
+ resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.27.7':
+ resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.27.7':
+ resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.27.7':
+ resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@koa/router@15.4.0':
+ resolution: {integrity: sha512-vKYlXtoCfcAN8z4dHiveYX55rTYOgHEYJNumK1WM9ZAwaArhreGVkyC1LTMGfUQUJyIO/SbwRFBOHeOCY8/MaQ==}
+ engines: {node: '>= 20'}
+ peerDependencies:
+ koa: ^2.0.0 || ^3.0.0
+
+ '@lezer/common@1.5.1':
+ resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==}
+
+ '@lezer/lr@1.4.8':
+ resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==}
+
+ '@lmdb/lmdb-darwin-arm64@2.8.5':
+ resolution: {integrity: sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@lmdb/lmdb-darwin-x64@2.8.5':
+ resolution: {integrity: sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@lmdb/lmdb-linux-arm64@2.8.5':
+ resolution: {integrity: sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@lmdb/lmdb-linux-arm@2.8.5':
+ resolution: {integrity: sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@lmdb/lmdb-linux-x64@2.8.5':
+ resolution: {integrity: sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@lmdb/lmdb-win32-x64@2.8.5':
+ resolution: {integrity: sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@mischnic/json-sourcemap@0.1.1':
+ resolution: {integrity: sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==}
+ engines: {node: '>=12.0.0'}
+
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
+ resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
+ resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
+ resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
+ resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
+ resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
+ resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/cache@2.16.4':
+ resolution: {integrity: sha512-+uCyeElSga2MBbmbXpIj/WVKH7TByCrKaxtHbelfKKIJpYMgEHVjO4cuc7GUfTrUAmRUS8ZGvnX7Etgq6/jQhw==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.16.4
+
+ '@parcel/codeframe@2.16.4':
+ resolution: {integrity: sha512-s64aMfOJoPrXhKH+Y98ahX0O8aXWvTR+uNlOaX4yFkpr4FFDnviLcGngDe/Yo4Qq2FJZ0P6dNswbJTUH9EGxkQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/core@2.16.4':
+ resolution: {integrity: sha512-a0CgrW5A5kwuSu5J1RFRoMQaMs9yagvfH2jJMYVw56+/7NRI4KOtu612SG9Y1ERWfY55ZwzyFxtLWvD6LO+Anw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/diagnostic@2.16.4':
+ resolution: {integrity: sha512-YN5CfX7lFd6yRLxyZT4Sj3sR6t7nnve4TdXSIqapXzQwL7Bw+sj79D95wTq2rCm3mzk5SofGxFAXul2/nG6gcQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/events@2.16.4':
+ resolution: {integrity: sha512-slWQkBRAA7o0cN0BLEd+yCckPmlVRVhBZn5Pn6ktm4EzEtrqoMzMeJOxxH8TXaRzrQDYnTcnYIHFgXWd4kkUfg==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/feature-flags@2.16.4':
+ resolution: {integrity: sha512-nYdx53siKPLYikHHxfzgjzzgxdrjquK6DMnuSgOTyIdRG4VHdEN0+NqKijRLuVgiUFo/dtxc2h+amwqFENMw8w==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/fs@2.16.4':
+ resolution: {integrity: sha512-maCMOiVn7oJYZlqlfxgLne8n6tSktIT1k0AeyBp4UGWCXyeJUJ+nL7QYShFpKNLtMLeF0cEtgwRAknWzbcDS1g==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.16.4
+
+ '@parcel/graph@3.6.4':
+ resolution: {integrity: sha512-Cj9yV+/k88kFhE+D+gz0YuNRpvNOCVDskO9pFqkcQhGbsGq6kg2XpZ9V7HlYraih31xf8Vb589bZOwjKIiHixQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/logger@2.16.4':
+ resolution: {integrity: sha512-QR8QLlKo7xAy9JBpPDAh0RvluaixqPCeyY7Fvo2K7hrU3r85vBNNi06pHiPbWoDmB4x1+QoFwMaGnJOHR+/fMA==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/markdown-ansi@2.16.4':
+ resolution: {integrity: sha512-0+oQApAVF3wMcQ6d1ZfZ0JsRzaMUYj9e4U+naj6YEsFsFGOPp+pQYKXBf1bobQeeB7cPKPT3SUHxFqced722Hw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/node-resolver-core@3.7.4':
+ resolution: {integrity: sha512-b3VDG+um6IWW5CTod6M9hQsTX5mdIelKmam7mzxzgqg4j5hnycgTWqPMc9UxhYoUY/Q/PHfWepccNcKtvP5JiA==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/package-manager@2.16.4':
+ resolution: {integrity: sha512-obWv9gZgdnkT3Kd+fBkKjhdNEY7zfOP5gVaox5i4nQstVCaVnDlMv5FwLEXwehL+WbwEcGyEGGxOHHkAFKk7Cg==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.16.4
+
+ '@parcel/plugin@2.16.4':
+ resolution: {integrity: sha512-aN2VQoRGC1eB41ZCDbPR/Sp0yKOxe31oemzPx1nJzOuebK2Q6FxSrJ9Bjj9j/YCaLzDtPwelsuLOazzVpXJ6qg==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/profiler@2.16.4':
+ resolution: {integrity: sha512-R3JhfcnoReTv2sVFHPR2xKZvs3d3IRrBl9sWmAftbIJFwT4rU70/W7IdwfaJVkD/6PzHq9mcgOh1WKL4KAxPdA==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/rust-darwin-arm64@2.16.4':
+ resolution: {integrity: sha512-P3Se36H9EO1fOlwXqQNQ+RsVKTGn5ztRSUGbLcT8ba6oOMmU1w7J4R810GgsCbwCuF10TJNUMkuD3Q2Sz15Q3Q==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/rust-darwin-x64@2.16.4':
+ resolution: {integrity: sha512-8aNKNyPIx3EthYpmVJevIdHmFsOApXAEYGi3HU69jTxLgSIfyEHDdGE9lEsMvhSrd/SSo4/euAtiV+pqK04wnA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/rust-linux-arm-gnueabihf@2.16.4':
+ resolution: {integrity: sha512-QrvqiSHaWRLc0JBHgUHVvDthfWSkA6AFN+ikV1UGENv4j2r/QgvuwJiG0VHrsL6pH5dRqj0vvngHzEgguke9DA==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/rust-linux-arm64-gnu@2.16.4':
+ resolution: {integrity: sha512-f3gBWQHLHRUajNZi3SMmDQiEx54RoRbXtZYQNuBQy7+NolfFcgb1ik3QhkT7xovuTF/LBmaqP3UFy0PxvR/iwQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/rust-linux-arm64-musl@2.16.4':
+ resolution: {integrity: sha512-cwml18RNKsBwHyZnrZg4jpecXkWjaY/mCArocWUxkFXjjB97L56QWQM9W86f2/Y3HcFcnIGJwx1SDDKJrV6OIA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/rust-linux-x64-gnu@2.16.4':
+ resolution: {integrity: sha512-0xIjQaN8hiG0F9R8coPYidHslDIrbfOS/qFy5GJNbGA3S49h61wZRBMQqa7JFW4+2T8R0J9j0SKHhLXpbLXrIg==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/rust-linux-x64-musl@2.16.4':
+ resolution: {integrity: sha512-fYn21GIecHK9RoZPKwT9NOwxwl3Gy3RYPR6zvsUi0+hpFo19Ph9EzFXN3lT8Pi5KiwQMCU4rsLb5HoWOBM1FeA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/rust-win32-x64-msvc@2.16.4':
+ resolution: {integrity: sha512-TcpWC3I1mJpfP2++018lgvM7UX0P8IrzNxceBTHUKEIDMwmAYrUKAQFiaU0j1Ldqk6yP8SPZD3cvphumsYpJOQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/rust@2.16.4':
+ resolution: {integrity: sha512-RBMKt9rCdv6jr4vXG6LmHtxzO5TuhQvXo1kSoSIF7fURRZ81D1jzBtLxwLmfxCPsofJNqWwdhy5vIvisX+TLlQ==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ napi-wasm: ^1.1.2
+ peerDependenciesMeta:
+ napi-wasm:
+ optional: true
+
+ '@parcel/source-map@2.1.1':
+ resolution: {integrity: sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==}
+ engines: {node: ^12.18.3 || >=14}
+
+ '@parcel/types-internal@2.16.4':
+ resolution: {integrity: sha512-PE6Qmt5cjzBxX+6MPLiF7r+twoC+V9Skt3zyuBQ+H1c0i9o07Bbz2NKX10nvlPukfmW6Fu/1RvTLkzBZR1bU6A==}
+
+ '@parcel/types@2.16.4':
+ resolution: {integrity: sha512-ctx4mBskZHXeDVHg4OjMwx18jfYH9BzI/7yqbDQVGvd5lyA+/oVVzYdpele2J2i2sSaJ87cA8nb57GDQ8kHAqA==}
+
+ '@parcel/utils@2.16.4':
+ resolution: {integrity: sha512-lkmxQHcHyOWZLbV8t+h2CGZIkPiBurLm/TS5wNT7+tq0qt9KbVwL7FP2K93TbXhLMGTmpI79Bf3qKniPM167Mw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/watcher-android-arm64@2.5.6':
+ resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.6':
+ resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.6':
+ resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.6':
+ resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.6':
+ resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-arm-musl@2.5.6':
+ resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.6':
+ resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.6':
+ resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.6':
+ resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@parcel/watcher-linux-x64-musl@2.5.6':
+ resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@parcel/watcher-win32-arm64@2.5.6':
+ resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.6':
+ resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.6':
+ resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.6':
+ resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
+ engines: {node: '>= 10.0.0'}
+
+ '@parcel/workers@2.16.4':
+ resolution: {integrity: sha512-dkBEWqnHXDZnRbTZouNt4uEGIslJT+V0c8OH1MPOfjISp1ucD6/u9ET8k9d/PxS9h1hL53og0SpBuuSEPLDl6A==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.16.4
+
+ '@swc/core-darwin-arm64@1.15.24':
+ resolution: {integrity: sha512-uM5ZGfFXjtvtJ+fe448PVBEbn/CSxS3UAyLj3O9xOqKIWy3S6hPTXSPbszxkSsGDYKi+YFhzAsR4r/eXLxEQ0g==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@swc/core-darwin-x64@1.15.24':
+ resolution: {integrity: sha512-fMIb/Zfn929pw25VMBhV7Ji2Dl+lCWtUPNdYJQYOke+00E5fcQ9ynxtP8+qhUo/HZc+mYQb1gJxwHM9vty+lXg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@swc/core-linux-arm-gnueabihf@1.15.24':
+ resolution: {integrity: sha512-vOkjsyjjxnoYx3hMEWcGxQrMgnNrRm6WAegBXrN8foHtDAR+zpdhpGF5a4lj1bNPgXAvmysjui8cM1ov/Clkaw==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@swc/core-linux-arm64-gnu@1.15.24':
+ resolution: {integrity: sha512-h/oNu+upkXJ6Cicnq7YGVj9PkdfarLCdQa8l/FlHYvfv8CEiMaeeTnpLU7gSBH/rGxosM6Qkfa/J9mThGF9CLA==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-arm64-musl@1.15.24':
+ resolution: {integrity: sha512-ZpF/pRe1guk6sKzQI9D1jAORtjTdNlyeXn9GDz8ophof/w2WhojRblvSDJaGe7rJjcPN8AaOkhwdRUh7q8oYIg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-linux-ppc64-gnu@1.15.24':
+ resolution: {integrity: sha512-QZEsZfisHTSJlmyChgDFNmKPb3W6Lhbfo/O76HhIngfEdnQNmukS38/VSe1feho+xkV5A5hETyCbx3sALBZKAQ==}
+ engines: {node: '>=10'}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-s390x-gnu@1.15.24':
+ resolution: {integrity: sha512-DLdJKVsJgglqQrJBuoUYNmzm3leI7kUZhLbZGHv42onfKsGf6JDS3+bzCUQfte/XOqDjh/tmmn1DR/CF/tCJFw==}
+ engines: {node: '>=10'}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-x64-gnu@1.15.24':
+ resolution: {integrity: sha512-IpLYfposPA/XLxYOKpRfeccl1p5dDa3+okZDHHTchBkXEaVCnq5MADPmIWwIYj1tudt7hORsEHccG5no6IUQRw==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-x64-musl@1.15.24':
+ resolution: {integrity: sha512-JHy3fMSc0t/EPWgo74+OK5TGr51aElnzqfUPaiRf2qJ/BfX5CUCfMiWVBuhI7qmVMBnk1jTRnL/xZnOSHDPLYg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-win32-arm64-msvc@1.15.24':
+ resolution: {integrity: sha512-Txj+qUH1z2bUd1P3JvwByfjKFti3cptlAxhWgmunBUUxy/IW3CXLZ6l6Gk4liANadKkU71nIU1X30Z5vpMT3BA==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@swc/core-win32-ia32-msvc@1.15.24':
+ resolution: {integrity: sha512-15D/nl3XwrhFpMv+MADFOiVwv3FvH9j8c6Rf8EXBT3Q5LoMh8YnDnSgPYqw1JzPnksvsBX6QPXLiPqmcR/Z4qQ==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@swc/core-win32-x64-msvc@1.15.24':
+ resolution: {integrity: sha512-PR0PlTlPra2JbaDphrOAzm6s0v9rA0F17YzB+XbWD95B4g2cWcZY9LAeTa4xll70VLw9Jr7xBrlohqlQmelMFQ==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@swc/core@1.15.24':
+ resolution: {integrity: sha512-5Hj8aNasue7yusUt8LGCUe/AjM7RMAce8ZoyDyiFwx7Al+GbYKL+yE7g4sJk8vEr1dKIkTRARkNIJENc4CjkBQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@swc/helpers': '>=0.5.17'
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+
+ '@swc/counter@0.1.3':
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
+ '@swc/helpers@0.5.21':
+ resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==}
+
+ '@swc/types@0.1.26':
+ resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==}
+
+ '@tech_query/node-toolkit@2.0.0-beta.3':
+ resolution: {integrity: sha512-ShhOWszgwwq19UlbtI8BCbPz7H4XLVk41fydKbUxwnVK1Fa24CE8imkPbddpOG3e6NEdOujKkCHKtAY84VVtqg==}
+ engines: {node: '>=20'}
+
+ '@tokenizer/token@0.3.0':
+ resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
+
+ '@types/accepts@1.3.7':
+ resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==}
+
+ '@types/body-parser@1.19.6':
+ resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
+
+ '@types/connect@3.4.38':
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+
+ '@types/content-disposition@0.5.9':
+ resolution: {integrity: sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ==}
+
+ '@types/cookies@0.9.2':
+ resolution: {integrity: sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A==}
+
+ '@types/express-serve-static-core@5.1.1':
+ resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
+
+ '@types/express@5.0.6':
+ resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
+
+ '@types/http-assert@1.5.6':
+ resolution: {integrity: sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==}
+
+ '@types/http-errors@2.0.5':
+ resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
+
+ '@types/keygrip@1.0.6':
+ resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
+
+ '@types/koa-compose@3.2.9':
+ resolution: {integrity: sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA==}
+
+ '@types/koa-send@4.1.6':
+ resolution: {integrity: sha512-vgnNGoOJkx7FrF0Jl6rbK1f8bBecqAchKpXtKuXzqIEdXTDO6dsSTjr+eZ5m7ltSjH4K/E7auNJEQCAd0McUPA==}
+
+ '@types/koa-static@4.0.4':
+ resolution: {integrity: sha512-j1AUzzl7eJYEk9g01hNTlhmipFh8RFbOQmaMNLvLcNNAkPw0bdTs3XTa3V045XFlrWN0QYnblbDJv2RzawTn6A==}
+
+ '@types/koa@3.0.2':
+ resolution: {integrity: sha512-7TRzVOBcH/q8CfPh9AmHBQ8TZtimT4Sn+rw8//hXveI6+F41z93W8a+0B0O8L7apKQv+vKBIEZSECiL0Oo1JFA==}
+
+ '@types/node@22.19.17':
+ resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==}
+
+ '@types/qs@6.15.0':
+ resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==}
+
+ '@types/range-parser@1.2.7':
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+
+ '@types/send@1.2.1':
+ resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
+
+ '@types/serve-static@2.2.0':
+ resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
+
+ '@types/whatwg-mimetype@3.0.2':
+ resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==}
+
+ '@types/ws@8.18.1':
+ resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+
+ abort-controller@3.0.0:
+ resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
+ engines: {node: '>=6.5'}
+
+ accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ base-x@3.0.11:
+ resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==}
+
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ baseline-browser-mapping@2.10.14:
+ resolution: {integrity: sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ browserslist@4.28.2:
+ resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ buffer@6.0.3:
+ resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+
+ caniuse-lite@1.0.30001785:
+ resolution: {integrity: sha512-blhOL/WNR+Km1RI/LCVAvA73xplXA7ZbjzI4YkMK9pa6T/P3F2GxjNpEkyw5repTw9IvkyrjyHpwjnhZ5FOvYQ==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ chrome-trace-event@1.0.4:
+ resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
+ engines: {node: '>=6.0'}
+
+ clone@2.1.2:
+ resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
+ engines: {node: '>=0.8'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ commander-jsx@0.7.3:
+ resolution: {integrity: sha512-x+/23MXIgJG2Z4p7lrXOL48GSEAHhmmyXIOuLLVEKaw/+P6h872aaghNBbw/8k08DUIAdEpnBW1qEWQ0oxHdfg==}
+
+ content-disposition@1.0.1:
+ resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==}
+ engines: {node: '>=18'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookies@0.9.1:
+ resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
+ engines: {node: '>= 0.8'}
+
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ declarative-shadow-dom-polyfill@0.4.1:
+ resolution: {integrity: sha512-Zot41HbLiffkkPFnsi55lMOtPj2TuUXShtTad/Ih5IIM7Am5XoNlGSJrJGGIiS7tFxsU67nraD9OSWBOXAuSsg==}
+ peerDependencies:
+ typescript: '>=5.5.3'
+
+ deep-equal@1.0.1:
+ resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==}
+
+ delegates@1.0.0:
+ resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
+
+ depd@1.1.2:
+ resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
+ engines: {node: '>= 0.6'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ dom-renderer@2.6.4:
+ resolution: {integrity: sha512-PLzT2nta96McrE4AvNPSntE13viZas7E9SmyEwp7sGda8Sawc1YBcrKz5AMD41UKJB/3lWBozlNraApC4nfUog==}
+ peerDependencies:
+ happy-dom: ^14
+
+ dotenv-expand@11.0.7:
+ resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==}
+ engines: {node: '>=12'}
+
+ dotenv@16.6.1:
+ resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
+ engines: {node: '>=12'}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ electron-to-chromium@1.5.331:
+ resolution: {integrity: sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==}
+
+ element-internals-polyfill@3.0.2:
+ resolution: {integrity: sha512-uB0/Qube3lkwh8SmkTnGIyUgJ9YdqVSzIoHMRCEQjAbD4Y5UzsVbch1tIxjTgUe5k3gy1U0ZMKMJ90A81lqwig==}
+
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
+ entities@7.0.1:
+ resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
+ engines: {node: '>=0.12'}
+
+ esbuild@0.27.7:
+ resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ event-target-shim@5.0.1:
+ resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
+ engines: {node: '>=6'}
+
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
+ file-type@16.5.4:
+ resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==}
+ engines: {node: '>=10'}
+
+ fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+
+ fs-extra@11.3.4:
+ resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==}
+ engines: {node: '>=14.14'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ get-tsconfig@4.13.7:
+ resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ happy-dom@20.8.9:
+ resolution: {integrity: sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==}
+ engines: {node: '>=20.0.0'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ http-assert@1.5.0:
+ resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==}
+ engines: {node: '>= 0.8'}
+
+ http-errors@1.6.3:
+ resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==}
+ engines: {node: '>= 0.6'}
+
+ http-errors@1.8.1:
+ resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
+ engines: {node: '>= 0.6'}
+
+ http-errors@2.0.1:
+ resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
+ engines: {node: '>= 0.8'}
+
+ ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+ inherits@2.0.3:
+ resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ jsonfile@6.2.0:
+ resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
+
+ keygrip@1.1.0:
+ resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
+ engines: {node: '>= 0.6'}
+
+ koa-compose@4.1.0:
+ resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==}
+
+ koa-send@5.0.1:
+ resolution: {integrity: sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==}
+ engines: {node: '>= 8'}
+
+ koa-static@5.0.0:
+ resolution: {integrity: sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==}
+ engines: {node: '>= 7.6.0'}
+
+ koa@3.2.0:
+ resolution: {integrity: sha512-TrM4/tnNY7uJ1aW55sIIa+dqBvc4V14WRIAlGcWat9wV5pRS9Wr5Zk2ZTjQP1jtfIHDoHiSbPuV08P0fUZo2pg==}
+ engines: {node: '>= 18'}
+
+ lmdb@2.8.5:
+ resolution: {integrity: sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==}
+ hasBin: true
+
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@3.0.2:
+ resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
+ engines: {node: '>=18'}
+
+ mime@3.0.0:
+ resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
+ engines: {node: '>=10.0.0'}
+ hasBin: true
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ msgpackr-extract@3.0.3:
+ resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==}
+ hasBin: true
+
+ msgpackr@1.11.9:
+ resolution: {integrity: sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==}
+
+ negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+
+ node-addon-api@6.1.0:
+ resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ node-gyp-build-optional-packages@5.1.1:
+ resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==}
+ hasBin: true
+
+ node-gyp-build-optional-packages@5.2.2:
+ resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
+ hasBin: true
+
+ node-releases@2.0.37:
+ resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==}
+
+ nullthrows@1.1.1:
+ resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ ordered-binary@1.6.1:
+ resolution: {integrity: sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
+ path-to-regexp@8.4.2:
+ resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
+
+ peek-readable@4.1.0:
+ resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ engines: {node: '>=12'}
+
+ process@0.11.10:
+ resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+ engines: {node: '>= 0.6.0'}
+
+ readable-stream@4.7.0:
+ resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ readable-web-to-node-stream@3.0.4:
+ resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==}
+ engines: {node: '>=8'}
+
+ regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+
+ resolve-path@1.4.0:
+ resolution: {integrity: sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==}
+ engines: {node: '>= 0.8'}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ scheduler-polyfill@1.3.0:
+ resolution: {integrity: sha512-bIjhi/KJqo08wrq+K2rlB6HNPh871KgREPpVti4zv0mSY1dCi3qr0rRCw+SGHc8/gtKceev29sN//lf6KiYa/g==}
+
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ setprototypeof@1.1.0:
+ resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ statuses@1.5.0:
+ resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
+ engines: {node: '>= 0.6'}
+
+ statuses@2.0.2:
+ resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
+ engines: {node: '>= 0.8'}
+
+ string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
+ strtok3@6.3.0:
+ resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==}
+ engines: {node: '>=10'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ token-types@4.2.1:
+ resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==}
+ engines: {node: '>=10'}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ tsscmp@1.0.6:
+ resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
+ engines: {node: '>=0.6.x'}
+
+ tsx@4.21.0:
+ resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
+ universalify@2.0.1:
+ resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+ engines: {node: '>= 10.0.0'}
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ utility-types@3.11.0:
+ resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
+ engines: {node: '>= 4'}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ weak-lru-cache@1.2.2:
+ resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==}
+
+ web-streams-polyfill@4.2.0:
+ resolution: {integrity: sha512-0rYDzGOh9EZpig92umN5g5D/9A1Kff7k0/mzPSSCY8jEQeYkgRMoY7LhbXtUCWzLCMX0TUE9aoHkjFNB7D9pfA==}
+ engines: {node: '>= 8'}
+
+ web-utility@4.6.5:
+ resolution: {integrity: sha512-1XsfSzTHUJB4qa7oiFkfKxUiVwMzZy7c8X4wTqno1ors8w6tFL/2kj+idoeCSXVh3OmCbcXhTldqGG7MbcP7FQ==}
+ peerDependencies:
+ element-internals-polyfill: '>=1'
+ typescript: '>=4.1'
+
+ whatwg-mimetype@3.0.0:
+ resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
+ engines: {node: '>=12'}
+
+ ws@8.20.0:
+ resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ yaml@2.8.3:
+ resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==}
+ engines: {node: '>= 14.6'}
+ hasBin: true
+
+snapshots:
+
+ '@esbuild/aix-ppc64@0.27.7':
+ optional: true
+
+ '@esbuild/android-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/android-arm@0.27.7':
+ optional: true
+
+ '@esbuild/android-x64@0.27.7':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/darwin-x64@0.27.7':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.27.7':
+ optional: true
+
+ '@esbuild/linux-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/linux-arm@0.27.7':
+ optional: true
+
+ '@esbuild/linux-ia32@0.27.7':
+ optional: true
+
+ '@esbuild/linux-loong64@0.27.7':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.27.7':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.27.7':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.27.7':
+ optional: true
+
+ '@esbuild/linux-s390x@0.27.7':
+ optional: true
+
+ '@esbuild/linux-x64@0.27.7':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.27.7':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.27.7':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/sunos-x64@0.27.7':
+ optional: true
+
+ '@esbuild/win32-arm64@0.27.7':
+ optional: true
+
+ '@esbuild/win32-ia32@0.27.7':
+ optional: true
+
+ '@esbuild/win32-x64@0.27.7':
+ optional: true
+
+ '@koa/router@15.4.0(koa@3.2.0)':
+ dependencies:
+ debug: 4.4.3
+ http-errors: 2.0.1
+ koa: 3.2.0
+ koa-compose: 4.1.0
+ path-to-regexp: 8.4.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@lezer/common@1.5.1': {}
+
+ '@lezer/lr@1.4.8':
+ dependencies:
+ '@lezer/common': 1.5.1
+
+ '@lmdb/lmdb-darwin-arm64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-darwin-x64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-arm64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-arm@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-x64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-win32-x64@2.8.5':
+ optional: true
+
+ '@mischnic/json-sourcemap@0.1.1':
+ dependencies:
+ '@lezer/common': 1.5.1
+ '@lezer/lr': 1.4.8
+ json5: 2.2.3
+
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
+ optional: true
+
+ '@parcel/cache@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@parcel/core': 2.16.4(@swc/helpers@0.5.21)
+ '@parcel/fs': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/logger': 2.16.4
+ '@parcel/utils': 2.16.4
+ lmdb: 2.8.5
+ transitivePeerDependencies:
+ - napi-wasm
+
+ '@parcel/codeframe@2.16.4':
+ dependencies:
+ chalk: 4.1.2
+
+ '@parcel/core@2.16.4(@swc/helpers@0.5.21)':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ '@parcel/cache': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/events': 2.16.4
+ '@parcel/feature-flags': 2.16.4
+ '@parcel/fs': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/graph': 3.6.4
+ '@parcel/logger': 2.16.4
+ '@parcel/package-manager': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))(@swc/helpers@0.5.21)
+ '@parcel/plugin': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/profiler': 2.16.4
+ '@parcel/rust': 2.16.4
+ '@parcel/source-map': 2.1.1
+ '@parcel/types': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/utils': 2.16.4
+ '@parcel/workers': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ base-x: 3.0.11
+ browserslist: 4.28.2
+ clone: 2.1.2
+ dotenv: 16.6.1
+ dotenv-expand: 11.0.7
+ json5: 2.2.3
+ msgpackr: 1.11.9
+ nullthrows: 1.1.1
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ - napi-wasm
+
+ '@parcel/diagnostic@2.16.4':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ nullthrows: 1.1.1
+
+ '@parcel/events@2.16.4': {}
+
+ '@parcel/feature-flags@2.16.4': {}
+
+ '@parcel/fs@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@parcel/core': 2.16.4(@swc/helpers@0.5.21)
+ '@parcel/feature-flags': 2.16.4
+ '@parcel/rust': 2.16.4
+ '@parcel/types-internal': 2.16.4
+ '@parcel/utils': 2.16.4
+ '@parcel/watcher': 2.5.6
+ '@parcel/workers': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ transitivePeerDependencies:
+ - napi-wasm
+
+ '@parcel/graph@3.6.4':
+ dependencies:
+ '@parcel/feature-flags': 2.16.4
+ nullthrows: 1.1.1
+
+ '@parcel/logger@2.16.4':
+ dependencies:
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/events': 2.16.4
+
+ '@parcel/markdown-ansi@2.16.4':
+ dependencies:
+ chalk: 4.1.2
+
+ '@parcel/node-resolver-core@3.7.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/fs': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/rust': 2.16.4
+ '@parcel/utils': 2.16.4
+ nullthrows: 1.1.1
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - '@parcel/core'
+ - napi-wasm
+
+ '@parcel/package-manager@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))(@swc/helpers@0.5.21)':
+ dependencies:
+ '@parcel/core': 2.16.4(@swc/helpers@0.5.21)
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/fs': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/logger': 2.16.4
+ '@parcel/node-resolver-core': 3.7.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/types': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@parcel/utils': 2.16.4
+ '@parcel/workers': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ '@swc/core': 1.15.24(@swc/helpers@0.5.21)
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ - napi-wasm
+
+ '@parcel/plugin@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@parcel/types': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ transitivePeerDependencies:
+ - '@parcel/core'
+ - napi-wasm
+
+ '@parcel/profiler@2.16.4':
+ dependencies:
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/events': 2.16.4
+ '@parcel/types-internal': 2.16.4
+ chrome-trace-event: 1.0.4
+
+ '@parcel/rust-darwin-arm64@2.16.4':
+ optional: true
+
+ '@parcel/rust-darwin-x64@2.16.4':
+ optional: true
+
+ '@parcel/rust-linux-arm-gnueabihf@2.16.4':
+ optional: true
+
+ '@parcel/rust-linux-arm64-gnu@2.16.4':
+ optional: true
+
+ '@parcel/rust-linux-arm64-musl@2.16.4':
+ optional: true
+
+ '@parcel/rust-linux-x64-gnu@2.16.4':
+ optional: true
+
+ '@parcel/rust-linux-x64-musl@2.16.4':
+ optional: true
+
+ '@parcel/rust-win32-x64-msvc@2.16.4':
+ optional: true
+
+ '@parcel/rust@2.16.4':
+ optionalDependencies:
+ '@parcel/rust-darwin-arm64': 2.16.4
+ '@parcel/rust-darwin-x64': 2.16.4
+ '@parcel/rust-linux-arm-gnueabihf': 2.16.4
+ '@parcel/rust-linux-arm64-gnu': 2.16.4
+ '@parcel/rust-linux-arm64-musl': 2.16.4
+ '@parcel/rust-linux-x64-gnu': 2.16.4
+ '@parcel/rust-linux-x64-musl': 2.16.4
+ '@parcel/rust-win32-x64-msvc': 2.16.4
+
+ '@parcel/source-map@2.1.1':
+ dependencies:
+ detect-libc: 1.0.3
+
+ '@parcel/types-internal@2.16.4':
+ dependencies:
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/feature-flags': 2.16.4
+ '@parcel/source-map': 2.1.1
+ utility-types: 3.11.0
+
+ '@parcel/types@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@parcel/types-internal': 2.16.4
+ '@parcel/workers': 2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))
+ transitivePeerDependencies:
+ - '@parcel/core'
+ - napi-wasm
+
+ '@parcel/utils@2.16.4':
+ dependencies:
+ '@parcel/codeframe': 2.16.4
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/logger': 2.16.4
+ '@parcel/markdown-ansi': 2.16.4
+ '@parcel/rust': 2.16.4
+ '@parcel/source-map': 2.1.1
+ chalk: 4.1.2
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - napi-wasm
+
+ '@parcel/watcher-android-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.6':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.6':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.6':
+ optional: true
+
+ '@parcel/watcher@2.5.6':
+ dependencies:
+ detect-libc: 2.1.2
+ is-glob: 4.0.3
+ node-addon-api: 7.1.1
+ picomatch: 4.0.4
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.6
+ '@parcel/watcher-darwin-arm64': 2.5.6
+ '@parcel/watcher-darwin-x64': 2.5.6
+ '@parcel/watcher-freebsd-x64': 2.5.6
+ '@parcel/watcher-linux-arm-glibc': 2.5.6
+ '@parcel/watcher-linux-arm-musl': 2.5.6
+ '@parcel/watcher-linux-arm64-glibc': 2.5.6
+ '@parcel/watcher-linux-arm64-musl': 2.5.6
+ '@parcel/watcher-linux-x64-glibc': 2.5.6
+ '@parcel/watcher-linux-x64-musl': 2.5.6
+ '@parcel/watcher-win32-arm64': 2.5.6
+ '@parcel/watcher-win32-ia32': 2.5.6
+ '@parcel/watcher-win32-x64': 2.5.6
+
+ '@parcel/workers@2.16.4(@parcel/core@2.16.4(@swc/helpers@0.5.21))':
+ dependencies:
+ '@parcel/core': 2.16.4(@swc/helpers@0.5.21)
+ '@parcel/diagnostic': 2.16.4
+ '@parcel/logger': 2.16.4
+ '@parcel/profiler': 2.16.4
+ '@parcel/types-internal': 2.16.4
+ '@parcel/utils': 2.16.4
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - napi-wasm
+
+ '@swc/core-darwin-arm64@1.15.24':
+ optional: true
+
+ '@swc/core-darwin-x64@1.15.24':
+ optional: true
+
+ '@swc/core-linux-arm-gnueabihf@1.15.24':
+ optional: true
+
+ '@swc/core-linux-arm64-gnu@1.15.24':
+ optional: true
+
+ '@swc/core-linux-arm64-musl@1.15.24':
+ optional: true
+
+ '@swc/core-linux-ppc64-gnu@1.15.24':
+ optional: true
+
+ '@swc/core-linux-s390x-gnu@1.15.24':
+ optional: true
+
+ '@swc/core-linux-x64-gnu@1.15.24':
+ optional: true
+
+ '@swc/core-linux-x64-musl@1.15.24':
+ optional: true
+
+ '@swc/core-win32-arm64-msvc@1.15.24':
+ optional: true
+
+ '@swc/core-win32-ia32-msvc@1.15.24':
+ optional: true
+
+ '@swc/core-win32-x64-msvc@1.15.24':
+ optional: true
+
+ '@swc/core@1.15.24(@swc/helpers@0.5.21)':
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.26
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.15.24
+ '@swc/core-darwin-x64': 1.15.24
+ '@swc/core-linux-arm-gnueabihf': 1.15.24
+ '@swc/core-linux-arm64-gnu': 1.15.24
+ '@swc/core-linux-arm64-musl': 1.15.24
+ '@swc/core-linux-ppc64-gnu': 1.15.24
+ '@swc/core-linux-s390x-gnu': 1.15.24
+ '@swc/core-linux-x64-gnu': 1.15.24
+ '@swc/core-linux-x64-musl': 1.15.24
+ '@swc/core-win32-arm64-msvc': 1.15.24
+ '@swc/core-win32-ia32-msvc': 1.15.24
+ '@swc/core-win32-x64-msvc': 1.15.24
+ '@swc/helpers': 0.5.21
+
+ '@swc/counter@0.1.3': {}
+
+ '@swc/helpers@0.5.21':
+ dependencies:
+ tslib: 2.8.1
+
+ '@swc/types@0.1.26':
+ dependencies:
+ '@swc/counter': 0.1.3
+
+ '@tech_query/node-toolkit@2.0.0-beta.3':
+ dependencies:
+ file-type: 16.5.4
+ fs-extra: 11.3.4
+ mime: 3.0.0
+ yaml: 2.8.3
+
+ '@tokenizer/token@0.3.0': {}
+
+ '@types/accepts@1.3.7':
+ dependencies:
+ '@types/node': 22.19.17
+
+ '@types/body-parser@1.19.6':
+ dependencies:
+ '@types/connect': 3.4.38
+ '@types/node': 22.19.17
+
+ '@types/connect@3.4.38':
+ dependencies:
+ '@types/node': 22.19.17
+
+ '@types/content-disposition@0.5.9': {}
+
+ '@types/cookies@0.9.2':
+ dependencies:
+ '@types/connect': 3.4.38
+ '@types/express': 5.0.6
+ '@types/keygrip': 1.0.6
+ '@types/node': 22.19.17
+
+ '@types/express-serve-static-core@5.1.1':
+ dependencies:
+ '@types/node': 22.19.17
+ '@types/qs': 6.15.0
+ '@types/range-parser': 1.2.7
+ '@types/send': 1.2.1
+
+ '@types/express@5.0.6':
+ dependencies:
+ '@types/body-parser': 1.19.6
+ '@types/express-serve-static-core': 5.1.1
+ '@types/serve-static': 2.2.0
+
+ '@types/http-assert@1.5.6': {}
+
+ '@types/http-errors@2.0.5': {}
+
+ '@types/keygrip@1.0.6': {}
+
+ '@types/koa-compose@3.2.9':
+ dependencies:
+ '@types/koa': 3.0.2
+
+ '@types/koa-send@4.1.6':
+ dependencies:
+ '@types/koa': 3.0.2
+
+ '@types/koa-static@4.0.4':
+ dependencies:
+ '@types/koa': 3.0.2
+ '@types/koa-send': 4.1.6
+
+ '@types/koa@3.0.2':
+ dependencies:
+ '@types/accepts': 1.3.7
+ '@types/content-disposition': 0.5.9
+ '@types/cookies': 0.9.2
+ '@types/http-assert': 1.5.6
+ '@types/http-errors': 2.0.5
+ '@types/keygrip': 1.0.6
+ '@types/koa-compose': 3.2.9
+ '@types/node': 22.19.17
+
+ '@types/node@22.19.17':
+ dependencies:
+ undici-types: 6.21.0
+
+ '@types/qs@6.15.0': {}
+
+ '@types/range-parser@1.2.7': {}
+
+ '@types/send@1.2.1':
+ dependencies:
+ '@types/node': 22.19.17
+
+ '@types/serve-static@2.2.0':
+ dependencies:
+ '@types/http-errors': 2.0.5
+ '@types/node': 22.19.17
+
+ '@types/whatwg-mimetype@3.0.2': {}
+
+ '@types/ws@8.18.1':
+ dependencies:
+ '@types/node': 22.19.17
+
+ abort-controller@3.0.0:
+ dependencies:
+ event-target-shim: 5.0.1
+
+ accepts@1.3.8:
+ dependencies:
+ mime-types: 2.1.35
+ negotiator: 0.6.3
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ base-x@3.0.11:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ base64-js@1.5.1: {}
+
+ baseline-browser-mapping@2.10.14: {}
+
+ browserslist@4.28.2:
+ dependencies:
+ baseline-browser-mapping: 2.10.14
+ caniuse-lite: 1.0.30001785
+ electron-to-chromium: 1.5.331
+ node-releases: 2.0.37
+ update-browserslist-db: 1.2.3(browserslist@4.28.2)
+
+ buffer@6.0.3:
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
+ caniuse-lite@1.0.30001785: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ chrome-trace-event@1.0.4: {}
+
+ clone@2.1.2: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ commander-jsx@0.7.3(element-internals-polyfill@3.0.2)(typescript@5.9.3):
+ dependencies:
+ '@tech_query/node-toolkit': 2.0.0-beta.3
+ tslib: 2.8.1
+ web-utility: 4.6.5(element-internals-polyfill@3.0.2)(typescript@5.9.3)
+ transitivePeerDependencies:
+ - element-internals-polyfill
+ - typescript
+
+ content-disposition@1.0.1: {}
+
+ content-type@1.0.5: {}
+
+ cookies@0.9.1:
+ dependencies:
+ depd: 2.0.0
+ keygrip: 1.1.0
+
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ declarative-shadow-dom-polyfill@0.4.1(typescript@5.9.3):
+ dependencies:
+ typescript: 5.9.3
+
+ deep-equal@1.0.1: {}
+
+ delegates@1.0.0: {}
+
+ depd@1.1.2: {}
+
+ depd@2.0.0: {}
+
+ destroy@1.2.0: {}
+
+ detect-libc@1.0.3: {}
+
+ detect-libc@2.1.2: {}
+
+ dom-renderer@2.6.4(element-internals-polyfill@3.0.2)(happy-dom@20.8.9)(typescript@5.9.3):
+ dependencies:
+ declarative-shadow-dom-polyfill: 0.4.1(typescript@5.9.3)
+ happy-dom: 20.8.9
+ scheduler-polyfill: 1.3.0
+ tslib: 2.8.1
+ web-streams-polyfill: 4.2.0
+ web-utility: 4.6.5(element-internals-polyfill@3.0.2)(typescript@5.9.3)
+ transitivePeerDependencies:
+ - element-internals-polyfill
+ - typescript
+
+ dotenv-expand@11.0.7:
+ dependencies:
+ dotenv: 16.6.1
+
+ dotenv@16.6.1: {}
+
+ ee-first@1.1.1: {}
+
+ electron-to-chromium@1.5.331: {}
+
+ element-internals-polyfill@3.0.2: {}
+
+ encodeurl@2.0.0: {}
+
+ entities@7.0.1: {}
+
+ esbuild@0.27.7:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.7
+ '@esbuild/android-arm': 0.27.7
+ '@esbuild/android-arm64': 0.27.7
+ '@esbuild/android-x64': 0.27.7
+ '@esbuild/darwin-arm64': 0.27.7
+ '@esbuild/darwin-x64': 0.27.7
+ '@esbuild/freebsd-arm64': 0.27.7
+ '@esbuild/freebsd-x64': 0.27.7
+ '@esbuild/linux-arm': 0.27.7
+ '@esbuild/linux-arm64': 0.27.7
+ '@esbuild/linux-ia32': 0.27.7
+ '@esbuild/linux-loong64': 0.27.7
+ '@esbuild/linux-mips64el': 0.27.7
+ '@esbuild/linux-ppc64': 0.27.7
+ '@esbuild/linux-riscv64': 0.27.7
+ '@esbuild/linux-s390x': 0.27.7
+ '@esbuild/linux-x64': 0.27.7
+ '@esbuild/netbsd-arm64': 0.27.7
+ '@esbuild/netbsd-x64': 0.27.7
+ '@esbuild/openbsd-arm64': 0.27.7
+ '@esbuild/openbsd-x64': 0.27.7
+ '@esbuild/openharmony-arm64': 0.27.7
+ '@esbuild/sunos-x64': 0.27.7
+ '@esbuild/win32-arm64': 0.27.7
+ '@esbuild/win32-ia32': 0.27.7
+ '@esbuild/win32-x64': 0.27.7
+
+ escalade@3.2.0: {}
+
+ escape-html@1.0.3: {}
+
+ event-target-shim@5.0.1: {}
+
+ events@3.3.0: {}
+
+ file-type@16.5.4:
+ dependencies:
+ readable-web-to-node-stream: 3.0.4
+ strtok3: 6.3.0
+ token-types: 4.2.1
+
+ fresh@0.5.2: {}
+
+ fs-extra@11.3.4:
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.2.0
+ universalify: 2.0.1
+
+ fsevents@2.3.3:
+ optional: true
+
+ get-tsconfig@4.13.7:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
+ graceful-fs@4.2.11: {}
+
+ happy-dom@20.8.9:
+ dependencies:
+ '@types/node': 22.19.17
+ '@types/whatwg-mimetype': 3.0.2
+ '@types/ws': 8.18.1
+ entities: 7.0.1
+ whatwg-mimetype: 3.0.0
+ ws: 8.20.0
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ has-flag@4.0.0: {}
+
+ http-assert@1.5.0:
+ dependencies:
+ deep-equal: 1.0.1
+ http-errors: 1.8.1
+
+ http-errors@1.6.3:
+ dependencies:
+ depd: 1.1.2
+ inherits: 2.0.3
+ setprototypeof: 1.1.0
+ statuses: 1.5.0
+
+ http-errors@1.8.1:
+ dependencies:
+ depd: 1.1.2
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 1.5.0
+ toidentifier: 1.0.1
+
+ http-errors@2.0.1:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.2
+ toidentifier: 1.0.1
+
+ ieee754@1.2.1: {}
+
+ inherits@2.0.3: {}
+
+ inherits@2.0.4: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ json5@2.2.3: {}
+
+ jsonfile@6.2.0:
+ dependencies:
+ universalify: 2.0.1
+ optionalDependencies:
+ graceful-fs: 4.2.11
+
+ keygrip@1.1.0:
+ dependencies:
+ tsscmp: 1.0.6
+
+ koa-compose@4.1.0: {}
+
+ koa-send@5.0.1:
+ dependencies:
+ debug: 4.4.3
+ http-errors: 1.8.1
+ resolve-path: 1.4.0
+ transitivePeerDependencies:
+ - supports-color
+
+ koa-static@5.0.0:
+ dependencies:
+ debug: 3.2.7
+ koa-send: 5.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ koa@3.2.0:
+ dependencies:
+ accepts: 1.3.8
+ content-disposition: 1.0.1
+ content-type: 1.0.5
+ cookies: 0.9.1
+ delegates: 1.0.0
+ destroy: 1.2.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ fresh: 0.5.2
+ http-assert: 1.5.0
+ http-errors: 2.0.1
+ koa-compose: 4.1.0
+ mime-types: 3.0.2
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.2
+ type-is: 2.0.1
+ vary: 1.1.2
+
+ lmdb@2.8.5:
+ dependencies:
+ msgpackr: 1.11.9
+ node-addon-api: 6.1.0
+ node-gyp-build-optional-packages: 5.1.1
+ ordered-binary: 1.6.1
+ weak-lru-cache: 1.2.2
+ optionalDependencies:
+ '@lmdb/lmdb-darwin-arm64': 2.8.5
+ '@lmdb/lmdb-darwin-x64': 2.8.5
+ '@lmdb/lmdb-linux-arm': 2.8.5
+ '@lmdb/lmdb-linux-arm64': 2.8.5
+ '@lmdb/lmdb-linux-x64': 2.8.5
+ '@lmdb/lmdb-win32-x64': 2.8.5
+
+ media-typer@1.1.0: {}
+
+ mime-db@1.52.0: {}
+
+ mime-db@1.54.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ mime-types@3.0.2:
+ dependencies:
+ mime-db: 1.54.0
+
+ mime@3.0.0: {}
+
+ ms@2.1.3: {}
+
+ msgpackr-extract@3.0.3:
+ dependencies:
+ node-gyp-build-optional-packages: 5.2.2
+ optionalDependencies:
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3
+ optional: true
+
+ msgpackr@1.11.9:
+ optionalDependencies:
+ msgpackr-extract: 3.0.3
+
+ negotiator@0.6.3: {}
+
+ node-addon-api@6.1.0: {}
+
+ node-addon-api@7.1.1: {}
+
+ node-gyp-build-optional-packages@5.1.1:
+ dependencies:
+ detect-libc: 2.1.2
+
+ node-gyp-build-optional-packages@5.2.2:
+ dependencies:
+ detect-libc: 2.1.2
+ optional: true
+
+ node-releases@2.0.37: {}
+
+ nullthrows@1.1.1: {}
+
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
+ ordered-binary@1.6.1: {}
+
+ parseurl@1.3.3: {}
+
+ path-is-absolute@1.0.1: {}
+
+ path-to-regexp@8.4.2: {}
+
+ peek-readable@4.1.0: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.4: {}
+
+ process@0.11.10: {}
+
+ readable-stream@4.7.0:
+ dependencies:
+ abort-controller: 3.0.0
+ buffer: 6.0.3
+ events: 3.3.0
+ process: 0.11.10
+ string_decoder: 1.3.0
+
+ readable-web-to-node-stream@3.0.4:
+ dependencies:
+ readable-stream: 4.7.0
+
+ regenerator-runtime@0.14.1: {}
+
+ resolve-path@1.4.0:
+ dependencies:
+ http-errors: 1.6.3
+ path-is-absolute: 1.0.1
+
+ resolve-pkg-maps@1.0.0: {}
+
+ safe-buffer@5.2.1: {}
+
+ scheduler-polyfill@1.3.0: {}
+
+ semver@7.7.4: {}
+
+ setprototypeof@1.1.0: {}
+
+ setprototypeof@1.2.0: {}
+
+ statuses@1.5.0: {}
+
+ statuses@2.0.2: {}
+
+ string_decoder@1.3.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ strtok3@6.3.0:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ peek-readable: 4.1.0
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ toidentifier@1.0.1: {}
+
+ token-types@4.2.1:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ ieee754: 1.2.1
+
+ tslib@2.8.1: {}
+
+ tsscmp@1.0.6: {}
+
+ tsx@4.21.0:
+ dependencies:
+ esbuild: 0.27.7
+ get-tsconfig: 4.13.7
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.2
+
+ typescript@5.9.3: {}
+
+ undici-types@6.21.0: {}
+
+ universalify@2.0.1: {}
+
+ update-browserslist-db@1.2.3(browserslist@4.28.2):
+ dependencies:
+ browserslist: 4.28.2
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ utility-types@3.11.0: {}
+
+ vary@1.1.2: {}
+
+ weak-lru-cache@1.2.2: {}
+
+ web-streams-polyfill@4.2.0: {}
+
+ web-utility@4.6.5(element-internals-polyfill@3.0.2)(typescript@5.9.3):
+ dependencies:
+ '@swc/helpers': 0.5.21
+ element-internals-polyfill: 3.0.2
+ regenerator-runtime: 0.14.1
+ typescript: 5.9.3
+
+ whatwg-mimetype@3.0.0: {}
+
+ ws@8.20.0: {}
+
+ yaml@2.8.3: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..6babe5e
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,6 @@
+allowBuilds:
+ '@parcel/watcher': false
+ '@swc/core': false
+ esbuild: false
+ lmdb: false
+ msgpackr-extract: false
diff --git a/source/cli.ts b/source/cli.ts
new file mode 100644
index 0000000..4309c41
--- /dev/null
+++ b/source/cli.ts
@@ -0,0 +1,151 @@
+/**
+ * WebSSR CLI – built with CommanderJSX.
+ *
+ * Uses the Command constructor API (not JSX syntax) so the file can share the
+ * same tsconfig (jsxImportSource: "dom-renderer") as the rest of the source
+ * tree without triggering a JSX-runtime namespace conflict.
+ */
+import './polyfill.js';
+
+import { join, resolve } from 'path';
+import { fileURLToPath } from 'url';
+import { dirname } from 'path';
+import { existsSync } from 'fs';
+
+import { Command } from 'commander-jsx';
+import type { Data } from 'commander-jsx';
+import Koa from 'koa';
+import serve from 'koa-static';
+
+import { createRouter } from './router.js';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+async function startServer(appDir: string, port: number) {
+ const app = new Koa();
+ const router = await createRouter(resolve(appDir));
+
+ app.use(router.routes());
+ app.use(router.allowedMethods());
+
+ // Serve pre-built client assets from `.webssr/dist`
+ const distDir = join(resolve(appDir), '..', '.webssr', 'dist');
+ if (existsSync(distDir)) {
+ app.use(serve(distDir));
+ }
+
+ app.listen(port, () =>
+ console.log(`WebSSR server listening on http://localhost:${port}`)
+ );
+}
+
+async function devCommand(options: Record) {
+ const port = Number(options['port'] ?? 3000);
+ const appDir = String(options['app'] ?? 'app');
+
+ console.log('[WebSSR] Starting development server…');
+
+ // Start Parcel bundler for client-side assets in watch mode
+ try {
+ const { default: Parcel } = await import('@parcel/core');
+ const bundler = new Parcel({
+ entries: join(resolve(appDir), '**', '*.client.tsx'),
+ defaultConfig: '@parcel/config-default',
+ mode: 'development',
+ hmrOptions: { port: port + 1 },
+ defaultTargetOptions: {
+ distDir: join(resolve(appDir), '..', '.webssr', 'dist'),
+ engines: { browsers: ['last 2 Chrome versions'] }
+ }
+ });
+
+ const subscription = await bundler.watch(err => {
+ if (err) console.error('[Parcel]', err);
+ });
+
+ process.on('SIGINT', () => {
+ void subscription.unsubscribe();
+ process.exit(0);
+ });
+ } catch {
+ // No client entry points found – proceed without Parcel bundler
+ }
+
+ await startServer(appDir, port);
+}
+
+async function startCommand(options: Record) {
+ const port = Number(options['port'] ?? 3000);
+ const appDir = String(options['app'] ?? 'app');
+ await startServer(appDir, port);
+}
+
+async function buildCommand(options: Record) {
+ const appDir = String(options['app'] ?? 'app');
+
+ console.log('[WebSSR] Building client assets…');
+
+ const { default: Parcel } = await import('@parcel/core');
+ const bundler = new Parcel({
+ entries: join(resolve(appDir), '**', '*.client.tsx'),
+ defaultConfig: '@parcel/config-default',
+ mode: 'production',
+ defaultTargetOptions: {
+ distDir: join(resolve(appDir), '..', '.webssr', 'dist'),
+ engines: { browsers: ['last 2 Chrome versions'] }
+ }
+ });
+
+ const { buildTime, bundleGraph } = await bundler.run();
+ const bundles = bundleGraph.getBundles();
+ console.log(`[WebSSR] Built ${bundles.length} bundle(s) in ${buildTime}ms`);
+}
+
+const { version } = (await import('../package.json', {
+ with: { type: 'json' }
+})) as { version: string };
+
+const portOption = {
+ port: {
+ shortcut: 'p',
+ parameters: '',
+ description: 'HTTP port (default: 3000)'
+ }
+};
+
+const appOption = {
+ app: {
+ shortcut: 'a',
+ parameters: '',
+ description: 'App directory (default: app)'
+ }
+};
+
+Command.execute(
+ new Command({
+ name: 'webssr',
+ version,
+ description: 'Web Components SSR framework',
+ children: [
+ new Command({
+ name: 'dev',
+ description: 'Start development server with hot reload',
+ options: { ...portOption, ...appOption },
+ executor: devCommand
+ }),
+ new Command({
+ name: 'start',
+ description: 'Start production server',
+ options: { ...portOption, ...appOption },
+ executor: startCommand
+ }),
+ new Command({
+ name: 'build',
+ description: 'Build client-side assets for production',
+ options: appOption,
+ executor: buildCommand
+ })
+ ]
+ }),
+ process.argv.slice(2)
+);
diff --git a/source/css-loader.ts b/source/css-loader.ts
new file mode 100644
index 0000000..738367d
--- /dev/null
+++ b/source/css-loader.ts
@@ -0,0 +1,24 @@
+/**
+ * Node.js ESM loader hook for CSS module files.
+ *
+ * Registered via `module.register()` in `polyfill.ts` so that `.css` imports
+ * inside server-rendered page components resolve without crashing Node.js.
+ *
+ * The stub exports an identity proxy: accessing any key returns the key string
+ * itself, so `styles.hero` yields `'hero'`. On the client side Parcel handles
+ * CSS modules properly with scoped class names; this stub is only for SSR.
+ */
+export function resolve(
+ specifier: string,
+ context: { parentURL?: string },
+ nextResolve: (specifier: string, context: { parentURL?: string }) => unknown
+) {
+ if (/\.(?:module\.)?css$/.test(specifier)) {
+ return {
+ url: `data:text/javascript,export default new Proxy({},{get:(_,k)=>k})`,
+ shortCircuit: true
+ };
+ }
+
+ return nextResolve(specifier, context);
+}
diff --git a/source/css-modules.d.ts b/source/css-modules.d.ts
new file mode 100644
index 0000000..5fd2ccf
--- /dev/null
+++ b/source/css-modules.d.ts
@@ -0,0 +1,12 @@
+/**
+ * Ambient type declaration for CSS Module files (`*.module.css`).
+ *
+ * When a page or component imports a CSS module, TypeScript treats the
+ * imported value as a plain `Record` mapping class-name
+ * identifiers to the scoped CSS class strings generated by the bundler
+ * (Parcel on the client, stub identity on the server during SSR).
+ */
+declare module '*.module.css' {
+ const classes: Record;
+ export default classes;
+}
diff --git a/source/index.ts b/source/index.ts
new file mode 100644
index 0000000..e156abb
--- /dev/null
+++ b/source/index.ts
@@ -0,0 +1,3 @@
+export { renderPage, renderPageToStream } from './renderer.js';
+export { createRouter } from './router.js';
+export type { PageComponent, PageProps } from './types.js';
diff --git a/source/parcel-plugin/index.ts b/source/parcel-plugin/index.ts
new file mode 100644
index 0000000..e07d5d9
--- /dev/null
+++ b/source/parcel-plugin/index.ts
@@ -0,0 +1,89 @@
+import { Transformer } from '@parcel/plugin';
+
+/**
+ * Parcel 2 Transformer – Client Component Boundary
+ *
+ * Intercepts imports that carry the `with { runtime: 'client' }` import
+ * attribute and rewrites them so that:
+ *
+ * • **Server builds** receive a lightweight stub object that preserves the
+ * component name and module specifier, enabling the SSR renderer to emit
+ * the right custom-element tag without executing client-only code.
+ *
+ * • **Client builds** are left unchanged so Parcel bundles the real
+ * component code for the browser.
+ *
+ * Usage in page / server components:
+ *
+ * ```ts
+ * import { MyButton } from './MyButton' with { runtime: 'client' };
+ * ```
+ *
+ * The build environment is detected via the `PARCEL_BUILD_TARGET` environment
+ * variable or, when absent, Parcel's asset `env.context` field.
+ */
+
+/**
+ * Regex that matches static import declarations with a `with { runtime: 'client' }` attribute.
+ *
+ * Captures:
+ * 1. Named imports clause (e.g. `MyButton, AnotherWidget`)
+ * 2. Module specifier (e.g. `./MyButton`)
+ */
+const CLIENT_IMPORT_RE =
+ /^import\s+\{([^}]+)\}\s+from\s+(['"])([^'"]+)\2\s+with\s+\{\s*runtime\s*:\s*['"]client['"]\s*\}\s*;?\s*$/gm;
+
+export default new Transformer({
+ async transform({ asset }) {
+ // Only process TypeScript / JavaScript source files
+ if (!['ts', 'tsx', 'js', 'jsx', 'mjs', 'mts'].includes(asset.type)) {
+ return [asset];
+ }
+
+ let code = await asset.getCode();
+
+ if (!CLIENT_IMPORT_RE.test(code)) {
+ // No client-component imports found – nothing to do
+ return [asset];
+ }
+
+ CLIENT_IMPORT_RE.lastIndex = 0;
+
+ const isServer =
+ asset.env.context === 'node' ||
+ asset.env.context === 'electron-main' ||
+ process.env['PARCEL_BUILD_TARGET'] === 'server';
+
+ if (!isServer) {
+ // Client build – leave the import untouched so Parcel bundles the
+ // real component code for the browser.
+ return [asset];
+ }
+
+ // Server build – replace each client-component import with a stub.
+ const transformed = code.replace(
+ CLIENT_IMPORT_RE,
+ (
+ _match: string,
+ imports: string,
+ _quote: string,
+ specifier: string
+ ) => {
+ const names = imports
+ .split(',')
+ .map((s: string) => s.trim())
+ .filter(Boolean);
+
+ return names
+ .map(
+ (name: string) =>
+ `const ${name} = { __clientComponent: true, specifier: ${JSON.stringify(specifier)}, name: ${JSON.stringify(name)} };`
+ )
+ .join('\n');
+ }
+ );
+
+ asset.setCode(transformed);
+ return [asset];
+ }
+});
diff --git a/source/polyfill.ts b/source/polyfill.ts
new file mode 100644
index 0000000..d4f8f04
--- /dev/null
+++ b/source/polyfill.ts
@@ -0,0 +1,48 @@
+/**
+ * Server-side DOM environment bootstrap.
+ *
+ * Two responsibilities:
+ * 1. Register a Node.js ESM loader hook that turns `.css` / `.module.css`
+ * imports into empty-object stubs so that page components can be loaded
+ * without triggering an "Unknown file extension" error in the SSR context.
+ * 2. Create a happy-dom `Window` and inject DOM globals into `globalThis` so
+ * `dom-renderer` can build and serialise virtual DOM nodes on the server.
+ *
+ * Import this module as the very first side-effect import in any server or
+ * test entry point.
+ */
+import { register } from 'module';
+import { pathToFileURL } from 'url';
+import { dirname, join } from 'path';
+import { fileURLToPath } from 'url';
+
+import { Window } from 'happy-dom';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+// Register the CSS-stub loader before any page component is dynamically imported
+register(
+ pathToFileURL(join(__dirname, 'css-loader.js')).href,
+ pathToFileURL(join(__dirname, '../'))
+);
+
+const window = new Window();
+
+const DOM_GLOBALS = [
+ 'window',
+ 'self',
+ 'XMLSerializer',
+ 'DOMParser',
+ 'NodeFilter',
+ 'Text',
+ 'Document',
+ 'document',
+ 'ShadowRoot',
+ 'Element',
+ 'HTMLElement',
+ 'HTMLUnknownElement'
+] as const;
+
+for (const key of DOM_GLOBALS) {
+ Reflect.set(globalThis, key, Reflect.get(window, key));
+}
diff --git a/source/renderer.ts b/source/renderer.ts
new file mode 100644
index 0000000..2594e2d
--- /dev/null
+++ b/source/renderer.ts
@@ -0,0 +1,78 @@
+import { DOMRenderer, type VNode } from 'dom-renderer';
+
+import type { PageComponent, PageProps } from './types.js';
+
+const renderer = new DOMRenderer();
+
+/**
+ * Declarative Shadow DOM polyfill script loaded from unpkg CDN.
+ * Browsers that do not yet natively support declarative shadow roots will
+ * use the polyfill from https://github.com/EasyWebApp/declarative-shadow-dom-polyfill.
+ */
+const POLYFILL_SCRIPT = ``;
+
+/**
+ * Wrap arbitrary page content in a minimal HTML document shell.
+ */
+function wrapDocument(body: string, clientScripts: string[] = []): string {
+ const scripts = clientScripts
+ .map(src => ``)
+ .join('\n');
+
+ return `
+
+
+
+
+${POLYFILL_SCRIPT}
+${scripts}
+
+
+${body}
+
+`;
+}
+
+/**
+ * Render an async page component to a complete HTML string.
+ */
+export async function renderPage(
+ Page: PageComponent,
+ props: PageProps,
+ clientScripts: string[] = []
+): Promise {
+ const vnode = await Page(props);
+ const content = renderer.renderToStaticMarkup(vnode as unknown as VNode);
+ return wrapDocument(content, clientScripts);
+}
+
+/**
+ * Async generator that yields the HTML document shell around streamed page
+ * content. Pipe it into a Node.js `Readable` with `Readable.from(stream)`.
+ */
+export async function* renderPageToStream(
+ Page: PageComponent,
+ props: PageProps,
+ clientScripts: string[] = []
+): AsyncGenerator {
+ const scripts = clientScripts
+ .map(src => ``)
+ .join('\n');
+
+ yield `
+
+
+
+
+${POLYFILL_SCRIPT}
+${scripts}
+
+
+`;
+
+ const vnode = await Page(props);
+
+ yield* renderer.renderToReadableStream(vnode as unknown as VNode);
+
+ yield '\n\n';
+}
diff --git a/source/router.ts b/source/router.ts
new file mode 100644
index 0000000..b2d1826
--- /dev/null
+++ b/source/router.ts
@@ -0,0 +1,98 @@
+import { readdir } from 'fs/promises';
+import { join, resolve } from 'path';
+import { pathToFileURL } from 'url';
+
+import Router from '@koa/router';
+import { Readable } from 'stream';
+
+import { renderPageToStream } from './renderer.js';
+import type { PageComponent } from './types.js';
+
+/**
+ * Recursively scan `dir` for `page.tsx` / `page.ts` files and return an
+ * array of `[routePath, absoluteFilePath]` pairs.
+ *
+ * Directory segments wrapped in square brackets (e.g. `[id]`) are treated as
+ * dynamic route parameters, following the Next.js App Router convention.
+ */
+async function scanPages(
+ dir: string,
+ basePath = ''
+): Promise<[string, string][]> {
+ const pages: [string, string][] = [];
+
+ let entries;
+ try {
+ entries = await readdir(dir, { withFileTypes: true });
+ } catch {
+ // Directory does not exist – silently return empty list
+ return pages;
+ }
+
+ for (const entry of entries) {
+ if (entry.isDirectory()) {
+ const sub = await scanPages(
+ join(dir, entry.name),
+ `${basePath}/${entry.name}`
+ );
+ pages.push(...sub);
+ } else if (
+ entry.name === 'page.tsx' ||
+ entry.name === 'page.ts'
+ ) {
+ pages.push([basePath || '/', join(dir, entry.name)]);
+ }
+ }
+
+ return pages;
+}
+
+/**
+ * Convert a Next.js App Router path segment (e.g. `/users/[id]/posts/[postId]`)
+ * into a Koa Router path (e.g. `/users/:id/posts/:postId`).
+ */
+function toKoaPath(routePath: string): string {
+ return routePath.replace(/\[([^\]]+)\]/g, ':$1');
+}
+
+/**
+ * Build a Koa Router by scanning `appDir` for page components.
+ *
+ * Each discovered `page.tsx` maps to a GET route that:
+ * 1. Dynamically imports the page module.
+ * 2. Calls the default-exported async page component.
+ * 3. Streams the declarative-shadow-DOM HTML response.
+ */
+export async function createRouter(appDir: string): Promise {
+ const router = new Router();
+ const pages = await scanPages(resolve(appDir));
+
+ for (const [routePath, filePath] of pages) {
+ const koaPath = toKoaPath(routePath);
+ const fileUrl = pathToFileURL(filePath).href;
+
+ router.get(koaPath, async ctx => {
+ const mod = await import(fileUrl);
+ const Page: PageComponent = mod.default;
+
+ if (typeof Page !== 'function') {
+ ctx.status = 404;
+ ctx.body = 'Page component not found';
+ return;
+ }
+
+ const params = ctx.params as Record;
+ const searchParams = Object.fromEntries(
+ new URLSearchParams(ctx.querystring)
+ );
+
+ ctx.type = 'text/html; charset=utf-8';
+ // Pipe the async-generator stream into the Koa (Node.js) response
+ ctx.body = Readable.from(
+ renderPageToStream(Page, { params, searchParams })
+ );
+ });
+ }
+
+ return router;
+}
diff --git a/source/server.ts b/source/server.ts
new file mode 100644
index 0000000..77bf9e6
--- /dev/null
+++ b/source/server.ts
@@ -0,0 +1,46 @@
+/**
+ * WebSSR – Koa HTTP server entry point.
+ *
+ * The DOM polyfill (happy-dom globals + CSS-module stub loader) must be
+ * bootstrapped before this file is evaluated. In the npm scripts this is
+ * done via `--import ./source/polyfill.ts`; when consumed programmatically
+ * import `./polyfill.js` as the very first side-effect in the entry point.
+ */
+import { fileURLToPath } from 'url';
+import { dirname, join, resolve } from 'path';
+import { existsSync } from 'fs';
+
+import Koa from 'koa';
+import serve from 'koa-static';
+
+import { createRouter } from './router.js';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+// Prefer the project-root `app/` directory; fall back to `test/app/` for dev
+const candidates = [
+ join(__dirname, '..', 'app'),
+ join(__dirname, '..', 'test', 'app')
+];
+const appDir = candidates.find(existsSync) ?? candidates[0];
+
+const app = new Koa();
+
+const router = await createRouter(resolve(appDir));
+
+app.use(router.routes());
+app.use(router.allowedMethods());
+
+// Serve any pre-built client assets from `.webssr/dist`
+const staticDir = join(__dirname, '..', '.webssr', 'dist');
+if (existsSync(staticDir)) {
+ app.use(serve(staticDir));
+}
+
+const PORT = process.env.PORT ? Number(process.env.PORT) : 3000;
+
+app.listen(PORT, () => {
+ console.log(`WebSSR server listening on http://localhost:${PORT}`);
+});
+
+export { app };
diff --git a/source/types.ts b/source/types.ts
new file mode 100644
index 0000000..64a2202
--- /dev/null
+++ b/source/types.ts
@@ -0,0 +1,8 @@
+export type PageProps = {
+ params: Record;
+ searchParams: Record;
+};
+
+export type PageComponent = (
+ props: PageProps
+) => JSX.Element | Promise;
diff --git a/test/app/about/page.tsx b/test/app/about/page.tsx
new file mode 100644
index 0000000..4b96991
--- /dev/null
+++ b/test/app/about/page.tsx
@@ -0,0 +1,24 @@
+import type { PageProps } from '../../../source/types.js';
+import { NavBar } from '../../components/NavBar.js';
+
+/**
+ * About page – `test/app/about/page.tsx` maps to the `/about` route.
+ */
+export default async function AboutPage(_props: PageProps) {
+ return (
+
+ About WebSSR
+
+ WebSSR is a lightweight server-side rendering framework for
+ Web Components. It follows the{' '}
+
+ Declarative Shadow DOM
+ {' '}
+ standard for HTML serialisation and DOM hydration, uses Koa
+ for the HTTP layer, and leverages Parcel 2 for client-side
+ bundling.
+
+
+
+ );
+}
diff --git a/test/app/page.tsx b/test/app/page.tsx
new file mode 100644
index 0000000..9292392
--- /dev/null
+++ b/test/app/page.tsx
@@ -0,0 +1,33 @@
+import type { PageProps } from '../../source/types.js';
+import { NavBar } from '../components/NavBar.js';
+import styles from '../styles/home.module.css';
+
+/**
+ * Home page – `test/app/page.tsx` maps to the `/` route in the test server.
+ *
+ * Demonstrates:
+ * - Async server component returning JSX
+ * - Sub-component import (` `)
+ * - CSS module import (`styles.hero`, `styles.title`)
+ */
+export default async function HomePage({ searchParams }: PageProps) {
+ const name = searchParams['name'] ?? 'World';
+
+ return (
+
+ Hello, {name}!
+
+ Welcome to WebSSR – a Web Components
+ server-side rendering framework built on{' '}
+
+ DOM-Renderer
+ {' '}
+ and Declarative Shadow DOM.
+
+
+
+ );
+}
diff --git a/test/components/NavBar.tsx b/test/components/NavBar.tsx
new file mode 100644
index 0000000..c40ccbb
--- /dev/null
+++ b/test/components/NavBar.tsx
@@ -0,0 +1,23 @@
+/**
+ * NavBar – a reusable navigation sub-component.
+ * Demonstrates that standard JSX sub-component imports work transparently
+ * in server-rendered pages.
+ */
+export interface NavBarProps {
+ links: { href: string; label: string }[];
+ className?: string;
+}
+
+export function NavBar({ links, className }: NavBarProps) {
+ return (
+
+
+ {links.map(({ href, label }) => (
+
+ {label}
+
+ ))}
+
+
+ );
+}
diff --git a/test/polyfill.ts b/test/polyfill.ts
new file mode 100644
index 0000000..3058ebe
--- /dev/null
+++ b/test/polyfill.ts
@@ -0,0 +1,5 @@
+/**
+ * Test-specific polyfill bootstrap – imported as the very first side effect
+ * in test files so DOM globals are available before any dom-renderer code runs.
+ */
+import '../source/polyfill.js';
diff --git a/test/renderer.test.tsx b/test/renderer.test.tsx
new file mode 100644
index 0000000..a021a6f
--- /dev/null
+++ b/test/renderer.test.tsx
@@ -0,0 +1,59 @@
+import './polyfill.js';
+import { describe, it } from 'node:test';
+import assert from 'node:assert/strict';
+
+import { renderPage, renderPageToStream } from '../source/renderer.js';
+import type { PageProps } from '../source/types.js';
+
+const BASE_PROPS: PageProps = { params: {}, searchParams: {} };
+
+describe('renderPage', () => {
+ it('returns a complete HTML document', async () => {
+ const Page = async (_props: PageProps) =>
+ (Hello Test ) as unknown as JSX.Element;
+
+ const html = await renderPage(Page, BASE_PROPS);
+ assert.match(html, //i);
+ assert.match(html, /Hello Test<\/h1>/);
+ assert.match(html, /<\/html>/);
+ });
+
+ it('injects the declarative-shadow-dom-polyfill script tag', async () => {
+ const Page = async (_props: PageProps) => (
) as unknown as JSX.Element;
+ const html = await renderPage(Page, BASE_PROPS);
+ assert.match(html, /declarative-shadow-dom-polyfill/);
+ });
+
+ it('interpolates searchParams into page output', async () => {
+ const Page = async ({ searchParams }: PageProps) =>
+ ({searchParams['name']}
) as unknown as JSX.Element;
+
+ const html = await renderPage(Page, {
+ params: {},
+ searchParams: { name: 'WebCell' }
+ });
+ assert.match(html, /WebCell/);
+ });
+
+ it('injects extra client script tags', async () => {
+ const Page = async (_props: PageProps) => (
) as unknown as JSX.Element;
+ const html = await renderPage(Page, BASE_PROPS, ['/client.js']);
+ assert.match(html, /src="\/client\.js"/);
+ });
+});
+
+describe('renderPageToStream', () => {
+ it('streams a complete HTML document via async generator', async () => {
+ const Page = async (_props: PageProps) => (Streamed ) as unknown as JSX.Element;
+
+ const chunks: string[] = [];
+ for await (const chunk of renderPageToStream(Page, BASE_PROPS)) {
+ chunks.push(chunk);
+ }
+
+ const html = chunks.join('');
+ assert.match(html, //i);
+ assert.match(html, /Streamed/);
+ assert.match(html, /<\/html>/);
+ });
+});
diff --git a/test/router.test.ts b/test/router.test.ts
new file mode 100644
index 0000000..d8961de
--- /dev/null
+++ b/test/router.test.ts
@@ -0,0 +1,27 @@
+import './polyfill.js';
+import { describe, it } from 'node:test';
+import assert from 'node:assert/strict';
+import { fileURLToPath } from 'url';
+import { dirname, join } from 'path';
+
+import { createRouter } from '../source/router.js';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const testAppDir = join(__dirname, 'app');
+
+describe('createRouter', () => {
+ it('registers GET routes for discovered page files', async () => {
+ const router = await createRouter(testAppDir);
+ const routes = router.stack.map(layer => String(layer.path));
+ assert.ok(routes.includes('/'), 'should include root route /');
+ assert.ok(routes.includes('/about'), 'should include /about route');
+ });
+
+ it('converts [param] segments to :param in route paths', async () => {
+ const router = await createRouter(testAppDir);
+ const paths = router.stack.map(layer => String(layer.path));
+ for (const p of paths) {
+ assert.ok(!p.includes('['), `route path should not contain '[': ${p}`);
+ }
+ });
+});
diff --git a/test/styles/home.module.css b/test/styles/home.module.css
new file mode 100644
index 0000000..c7b8330
--- /dev/null
+++ b/test/styles/home.module.css
@@ -0,0 +1,14 @@
+.hero {
+ padding: 2rem;
+ background: #f0f4ff;
+ border-radius: 8px;
+}
+
+.title {
+ font-size: 2rem;
+ color: #1a1a2e;
+}
+
+.nav {
+ margin-top: 1rem;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..a80b645
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
+ "jsx": "react-jsx",
+ "jsxImportSource": "dom-renderer",
+ "strict": true,
+ "skipLibCheck": true,
+ "outDir": "dist",
+ "rootDir": ".",
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true
+ },
+ "include": ["source/**/*", "test/**/*"],
+ "exclude": ["node_modules", "dist"]
+}