diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2ebce92
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+node_modules/
+dist/
+coverage/
+
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+*.tsbuildinfo
+.vite/
+.cache/
+.eslintcache
+
+.DS_Store
+Thumbs.db
+
+.idea/
+.vscode/
+
+.env
+.env.local
+.env.*.local
+
+wallet.json
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..15feef2
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,18 @@
+Look at bundle-uploader/arghost.js for a guide on how the manifest to power this blog is generated.
+
+We are starting with arweave.net/VKzmyjIucGm2t9XBYNXpP0aolCD10CfEkivJvRnTpp4 as the manifest.
+
+Inside you have a JSON of arweave.net txids for the blog, which need rendering as an index and as /slug -> load single post.
+
+We want:
+
+* Markdown -> html engine, use something that exists and is the robust standard
+* A minimal blog template. Light theme, only black and white.
+* Pretty individual post view, with metadata from the manifest
+* Nice index view
+
+The look and feel is a modern, elegant, developer-focused light-theme blog. No rounded corners.
+
+Ideal flow going forward: I update some const with the manifest view whenever I make an update to the blog.
+
+The blog is called Hyperzine.
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..7127fae
--- /dev/null
+++ b/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ hyperzine
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..1610dbf
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2167 @@
+{
+ "name": "hyperzine",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "hyperzine",
+ "version": "0.0.0",
+ "dependencies": {
+ "arweave": "^1.15.7",
+ "dompurify": "^3.2.6",
+ "marked": "^15.0.12",
+ "mime-types": "^3.0.1",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.5.3",
+ "warp-arbundles": "^1.0.4",
+ "yaml": "^2.8.1"
+ },
+ "devDependencies": {
+ "@types/node": "^22.15.0",
+ "@types/react": "^19.1.2",
+ "@types/react-dom": "^19.1.2",
+ "@vitejs/plugin-react": "^4.4.1",
+ "typescript": "~5.8.3",
+ "vite": "^6.3.5"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.0.tgz",
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.1",
+ "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.2.tgz",
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.2.tgz",
+ "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@fastify/busboy": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmmirror.com/@fastify/busboy/-/busboy-2.1.1.tgz",
+ "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz",
+ "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz",
+ "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz",
+ "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz",
+ "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz",
+ "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz",
+ "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz",
+ "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz",
+ "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz",
+ "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz",
+ "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz",
+ "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz",
+ "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz",
+ "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz",
+ "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz",
+ "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz",
+ "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz",
+ "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz",
+ "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz",
+ "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz",
+ "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz",
+ "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz",
+ "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz",
+ "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz",
+ "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz",
+ "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmmirror.com/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmmirror.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.15",
+ "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.15.tgz",
+ "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.14",
+ "resolved": "https://registry.npmmirror.com/@types/react/-/react-19.2.14.tgz",
+ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/arconnect": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmmirror.com/arconnect/-/arconnect-0.4.2.tgz",
+ "integrity": "sha512-Jkpd4QL3TVqnd3U683gzXmZUVqBUy17DdJDuL/3D9rkysLgX6ymJ2e+sR+xyZF5Rh42CBqDXWNMmCjBXeP7Gbw==",
+ "license": "MIT",
+ "dependencies": {
+ "arweave": "^1.10.13"
+ }
+ },
+ "node_modules/arweave": {
+ "version": "1.15.7",
+ "resolved": "https://registry.npmmirror.com/arweave/-/arweave-1.15.7.tgz",
+ "integrity": "sha512-F+Y4iWU1qea9IsKQ/YNmLsY4DHQVsaJBuhEbFxQn9cfGHOmtXE+bwo14oY8xqymsqSNf/e1PeIfLk7G7qN/hVA==",
+ "license": "MIT",
+ "dependencies": {
+ "arconnect": "^0.4.2",
+ "asn1.js": "^5.4.1",
+ "base64-js": "^1.5.1",
+ "bignumber.js": "^9.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/asn1.js": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmmirror.com/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+ "license": "MIT",
+ "dependencies": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/base64url": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmmirror.com/base64url/-/base64url-3.0.1.tgz",
+ "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.10",
+ "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz",
+ "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/bignumber.js": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz",
+ "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/bn.js": {
+ "version": "4.12.3",
+ "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.3.tgz",
+ "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==",
+ "license": "MIT"
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.1",
+ "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz",
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "baseline-browser-mapping": "^2.9.0",
+ "caniuse-lite": "^1.0.30001759",
+ "electron-to-chromium": "^1.5.263",
+ "node-releases": "^2.0.27",
+ "update-browserslist-db": "^1.2.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001781",
+ "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz",
+ "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dompurify": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.3.3.tgz",
+ "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.325",
+ "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.325.tgz",
+ "integrity": "sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/marked": {
+ "version": "15.0.12",
+ "resolved": "https://registry.npmmirror.com/marked/-/marked-15.0.12.tgz",
+ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "license": "ISC"
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.36",
+ "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.36.tgz",
+ "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.8",
+ "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.8.tgz",
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmmirror.com/react/-/react-19.2.4.tgz",
+ "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.4.tgz",
+ "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.4"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-router": {
+ "version": "7.13.2",
+ "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.13.2.tgz",
+ "integrity": "sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.13.2",
+ "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.13.2.tgz",
+ "integrity": "sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.13.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.60.0.tgz",
+ "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.60.0",
+ "@rollup/rollup-android-arm64": "4.60.0",
+ "@rollup/rollup-darwin-arm64": "4.60.0",
+ "@rollup/rollup-darwin-x64": "4.60.0",
+ "@rollup/rollup-freebsd-arm64": "4.60.0",
+ "@rollup/rollup-freebsd-x64": "4.60.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.60.0",
+ "@rollup/rollup-linux-arm64-musl": "4.60.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.60.0",
+ "@rollup/rollup-linux-loong64-musl": "4.60.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.60.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.60.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.60.0",
+ "@rollup/rollup-linux-x64-gnu": "4.60.0",
+ "@rollup/rollup-linux-x64-musl": "4.60.0",
+ "@rollup/rollup-openbsd-x64": "4.60.0",
+ "@rollup/rollup-openharmony-arm64": "4.60.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.60.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.60.0",
+ "@rollup/rollup-win32-x64-gnu": "4.60.0",
+ "@rollup/rollup-win32-x64-msvc": "4.60.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmmirror.com/undici/-/undici-5.29.0.tgz",
+ "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
+ "license": "MIT",
+ "dependencies": {
+ "@fastify/busboy": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmmirror.com/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/warp-arbundles": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/warp-arbundles/-/warp-arbundles-1.0.4.tgz",
+ "integrity": "sha512-KeRac/EJ7VOK+v5+PSMh2SrzpCKOAFnJICLlqZWt6qPkDCzVwcrNE5wFxOlEk5U170ewMDAB3e86UHUblevXpw==",
+ "license": "ISC",
+ "dependencies": {
+ "arweave": "^1.13.7",
+ "base64url": "^3.0.1",
+ "buffer": "^6.0.3",
+ "warp-isomorphic": "^1.0.7"
+ }
+ },
+ "node_modules/warp-isomorphic": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmmirror.com/warp-isomorphic/-/warp-isomorphic-1.0.7.tgz",
+ "integrity": "sha512-fXHbUXwdYqPm9fRPz8mjv5ndPco09aMQuTe4kXfymzOq8V6F3DLsg9cIafxvjms9/mc6eijzkLBJ63yjEENEjA==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^6.0.3",
+ "undici": "^5.19.1"
+ },
+ "engines": {
+ "node": ">=16.8.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.3.tgz",
+ "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
+ "license": "ISC",
+ "peer": true,
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e2b5e99
--- /dev/null
+++ b/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "hyperzine",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview",
+ "wallet:new": "node scripts/generate-wallet.mjs",
+ "deploy": "node scripts/deploy.mjs --app-name=hyperzine --app-version=1.0.0",
+ "deploy:up": "npm run build && node scripts/deploy-up.mjs",
+ "ship": "node scripts/ship.mjs"
+ },
+ "dependencies": {
+ "arweave": "^1.15.7",
+ "dompurify": "^3.2.6",
+ "marked": "^15.0.12",
+ "mime-types": "^3.0.1",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.5.3",
+ "warp-arbundles": "^1.0.4",
+ "yaml": "^2.8.1"
+ },
+ "devDependencies": {
+ "@types/node": "^22.15.0",
+ "@types/react": "^19.1.2",
+ "@types/react-dom": "^19.1.2",
+ "@vitejs/plugin-react": "^4.4.1",
+ "typescript": "~5.8.3",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/scripts/deploy-up.mjs b/scripts/deploy-up.mjs
new file mode 100644
index 0000000..6f8695d
--- /dev/null
+++ b/scripts/deploy-up.mjs
@@ -0,0 +1,47 @@
+import path from "node:path";
+import { spawn } from "node:child_process";
+
+const root = process.cwd();
+
+function parseArg(name) {
+ const raw = process.argv.find((arg) => arg.startsWith(`--${name}=`));
+ if (!raw) return "";
+ return raw.slice(name.length + 3).trim();
+}
+
+function runNodeScript(scriptPath, args) {
+ return new Promise((resolve, reject) => {
+ const child = spawn(process.execPath, [scriptPath, ...args], {
+ cwd: root,
+ stdio: "inherit"
+ });
+ child.on("error", reject);
+ child.on("close", (code) => {
+ if (code !== 0) {
+ reject(new Error(`Deploy failed with exit code ${code}`));
+ return;
+ }
+ resolve();
+ });
+ });
+}
+
+async function main() {
+ const walletArg = parseArg("wallet");
+ const gatewayArg = parseArg("gateway");
+ const appName = parseArg("app-name");
+ const appVersion = parseArg("app-version");
+
+ await runNodeScript(path.join(root, "scripts", "deploy.mjs"), [
+ "--upload-mode=up",
+ ...(walletArg ? [`--wallet=${walletArg}`] : []),
+ ...(gatewayArg ? [`--gateway=${gatewayArg}`] : []),
+ ...(appName ? [`--app-name=${appName}`] : []),
+ ...(appVersion ? [`--app-version=${appVersion}`] : [])
+ ]);
+}
+
+main().catch((error) => {
+ console.error(error?.message || String(error));
+ process.exit(1);
+});
diff --git a/scripts/deploy.mjs b/scripts/deploy.mjs
new file mode 100644
index 0000000..fea4853
--- /dev/null
+++ b/scripts/deploy.mjs
@@ -0,0 +1,356 @@
+import fs from "node:fs/promises";
+import path from "node:path";
+import { gzipSync } from "node:zlib";
+import { spawn } from "node:child_process";
+import Arweave from "arweave";
+import mime from "mime-types";
+import arbundles from "warp-arbundles";
+
+const { createData, ArweaveSigner } = arbundles;
+
+const root = process.cwd();
+const distDir = path.join(root, "dist");
+const sourceConfigPath = path.join(root, "src", "config.ts");
+const DEFAULT_GATEWAY = "https://arweave.net";
+const DEFAULT_UPLOAD_MODE = "arweave";
+const UP_UPLOAD_MODE = "up";
+const SUPPORTED_UPLOAD_MODES = new Set([DEFAULT_UPLOAD_MODE, UP_UPLOAD_MODE]);
+const DEFAULT_UP_UPLOAD_SERVICE = "https://up.arweave.net";
+
+function parseArg(name) {
+ const raw = process.argv.find((arg) => arg.startsWith(`--${name}=`));
+ if (!raw) return "";
+ return raw.slice(name.length + 3).trim();
+}
+
+function buildGatewayConfig(gateway) {
+ const parsed = new URL(gateway);
+ return {
+ host: parsed.hostname,
+ port: parsed.port ? Number.parseInt(parsed.port, 10) : parsed.protocol === "https:" ? 443 : 80,
+ protocol: parsed.protocol.replace(":", "")
+ };
+}
+
+async function pathExists(targetPath) {
+ try {
+ await fs.access(targetPath);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+async function listFiles(dir) {
+ const entries = await fs.readdir(dir, { withFileTypes: true });
+ const nested = await Promise.all(
+ entries.map(async (entry) => {
+ const absolutePath = path.join(dir, entry.name);
+ if (entry.isDirectory()) return listFiles(absolutePath);
+ return [absolutePath];
+ })
+ );
+ return nested.flat();
+}
+
+function runBinary(command, args, cwd) {
+ return new Promise((resolve, reject) => {
+ const child = spawn(command, args, {
+ cwd,
+ stdio: ["ignore", "pipe", "pipe"]
+ });
+
+ const stdoutChunks = [];
+ let stderr = "";
+
+ child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
+ child.stderr.on("data", (chunk) => {
+ stderr += chunk.toString();
+ });
+
+ child.on("error", reject);
+ child.on("close", (code) => {
+ if (code !== 0) {
+ reject(new Error(`${command} exited with code ${code}${stderr ? `: ${stderr.trim()}` : ""}`));
+ return;
+ }
+ resolve({ stdout: Buffer.concat(stdoutChunks), stderr });
+ });
+ });
+}
+
+async function createCodeArchiveBuffer() {
+ const { stdout } = await runBinary(
+ "tar",
+ ["--exclude=./node_modules", "--exclude=./wallet.json", "-cf", "-", "."],
+ root
+ );
+ return gzipSync(stdout);
+}
+
+async function loadWallet(arweave, walletArg) {
+ const envWallet = process.env.ARWEAVE_WALLET?.trim();
+
+ if (walletArg) {
+ const absoluteWalletPath = path.resolve(root, walletArg);
+ if (!(await pathExists(absoluteWalletPath))) {
+ throw new Error(`Wallet file not found: ${absoluteWalletPath}`);
+ }
+ const jwkRaw = await fs.readFile(absoluteWalletPath, "utf8");
+ return { walletPath: absoluteWalletPath, generated: false, jwk: JSON.parse(jwkRaw) };
+ }
+
+ if (envWallet) {
+ const absoluteWalletPath = path.resolve(root, envWallet);
+ if (!(await pathExists(absoluteWalletPath))) {
+ throw new Error(`ARWEAVE_WALLET points to a missing file: ${absoluteWalletPath}`);
+ }
+ const jwkRaw = await fs.readFile(absoluteWalletPath, "utf8");
+ return { walletPath: absoluteWalletPath, generated: false, jwk: JSON.parse(jwkRaw) };
+ }
+
+ const defaultWalletPath = path.join(root, "wallet.json");
+ if (!(await pathExists(defaultWalletPath))) {
+ const jwk = await arweave.wallets.generate();
+ await fs.writeFile(defaultWalletPath, `${JSON.stringify(jwk, null, 2)}\n`, "utf8");
+ return { walletPath: defaultWalletPath, generated: true, jwk };
+ }
+
+ const jwkRaw = await fs.readFile(defaultWalletPath, "utf8");
+ return { walletPath: defaultWalletPath, generated: false, jwk: JSON.parse(jwkRaw) };
+}
+
+async function uploadTransaction(arweave, jwk, data, tags) {
+ const tx = await arweave.createTransaction({ data }, jwk);
+ for (const [key, value] of tags) tx.addTag(key, value);
+
+ await arweave.transactions.sign(tx, jwk);
+ const uploader = await arweave.transactions.getUploader(tx);
+ while (!uploader.isComplete) await uploader.uploadChunk();
+ return tx.id;
+}
+
+function sleep(ms) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+function isRetriableUploadError(message) {
+ return (
+ message.includes("timeout") ||
+ message.includes("504") ||
+ message.includes("502") ||
+ message.includes("503") ||
+ message.includes("429") ||
+ message.includes("EAI_AGAIN") ||
+ message.includes("ECONNRESET") ||
+ message.includes("failed to fetch")
+ );
+}
+
+async function uploadWithUpService(serviceUrl, signer, data, tags) {
+ const payload = Buffer.isBuffer(data) ? data : Buffer.from(data);
+ const dataItem = createData(payload, signer, {
+ tags: tags.map(([name, value]) => ({ name, value }))
+ });
+ await dataItem.sign(signer);
+ const txId = await dataItem.id;
+
+ for (let attempt = 1; attempt <= 3; attempt += 1) {
+ try {
+ const response = await fetch(`${serviceUrl.replace(/\/+$/, "")}/tx`, {
+ method: "POST",
+ headers: { "content-type": "application/octet-stream" },
+ body: dataItem.getRaw()
+ });
+
+ const bodyText = await response.text();
+ if (!response.ok) {
+ throw new Error(
+ `up upload failed (${response.status}${bodyText ? `): ${bodyText.slice(0, 220)}` : ")"}`
+ );
+ }
+
+ let responseTxId = "";
+ try {
+ const bodyJson = JSON.parse(bodyText);
+ if (typeof bodyJson?.id === "string") responseTxId = bodyJson.id.trim();
+ } catch {
+ responseTxId = bodyText.trim();
+ }
+
+ return responseTxId || txId;
+ } catch (error) {
+ const message = error?.message || String(error);
+ if (!isRetriableUploadError(message) || attempt === 3) throw error;
+ await sleep(1500 * attempt);
+ }
+ }
+
+ throw new Error("up upload failed unexpectedly.");
+}
+
+function resolveUploadMode(uploadModeArg) {
+ const mode = (uploadModeArg || process.env.ARWEAVE_UPLOAD_MODE || DEFAULT_UPLOAD_MODE).trim();
+ if (!SUPPORTED_UPLOAD_MODES.has(mode)) {
+ throw new Error(
+ `Unsupported upload mode "${mode}". Supported values: ${[...SUPPORTED_UPLOAD_MODES].join(", ")}`
+ );
+ }
+ return mode;
+}
+
+async function createUploader(uploadMode, arweave, jwk) {
+ if (uploadMode === DEFAULT_UPLOAD_MODE) {
+ return {
+ mode: DEFAULT_UPLOAD_MODE,
+ serviceUrl: null,
+ async beforeUpload() {},
+ upload(data, tags) {
+ return uploadTransaction(arweave, jwk, data, tags);
+ }
+ };
+ }
+
+ const signer = new ArweaveSigner(jwk);
+ return {
+ mode: UP_UPLOAD_MODE,
+ serviceUrl: DEFAULT_UP_UPLOAD_SERVICE,
+ async beforeUpload() {},
+ upload(data, tags) {
+ return uploadWithUpService(DEFAULT_UP_UPLOAD_SERVICE, signer, data, tags);
+ }
+ };
+}
+
+async function resolveBlogManifestTxId() {
+ const source = await fs.readFile(sourceConfigPath, "utf8");
+ const match = source.match(/MANIFEST_TX_ID\s*=\s*"([^"]+)"/);
+ return match?.[1] || "";
+}
+
+async function resolvePostSlugs(gateway) {
+ const blogManifestTxId = await resolveBlogManifestTxId();
+ if (!blogManifestTxId) return [];
+
+ try {
+ const response = await fetch(`${gateway.replace(/\/+$/, "")}/${blogManifestTxId}`);
+ if (!response.ok) return [];
+ const payload = await response.json();
+ if (!Array.isArray(payload?.posts)) return [];
+ return payload.posts
+ .map((post) => (typeof post?.slug === "string" ? post.slug.trim() : ""))
+ .filter((slug) => slug.length > 0);
+ } catch {
+ return [];
+ }
+}
+
+async function main() {
+ const walletArg = parseArg("wallet");
+ const gatewayArg = parseArg("gateway");
+ const uploadModeArg = parseArg("upload-mode");
+ const appName = parseArg("app-name") || "hyperzine";
+ const appVersion = parseArg("app-version") || "1.0.0";
+ const uploadMode = resolveUploadMode(uploadModeArg);
+ const gateway = gatewayArg || process.env.ARWEAVE_GATEWAY || DEFAULT_GATEWAY;
+
+ if (!(await pathExists(distDir))) {
+ throw new Error("dist/ is missing. Run npm run build first.");
+ }
+
+ const arweave = Arweave.init({
+ ...buildGatewayConfig(gateway),
+ timeout: 30_000,
+ logging: false
+ });
+
+ const { walletPath, generated, jwk } = await loadWallet(arweave, walletArg);
+ console.log(`${generated ? "Generated" : "Using"} wallet: ${walletPath}`);
+ console.log(`Gateway: ${gateway}`);
+ console.log(`Upload mode: ${uploadMode}`);
+
+ const uploader = await createUploader(uploadMode, arweave, jwk);
+ if (uploader.serviceUrl) console.log(`Upload service: ${uploader.serviceUrl}`);
+ await uploader.beforeUpload();
+
+ const filePaths = await listFiles(distDir);
+ if (!filePaths.length) {
+ throw new Error("dist/ is empty. Run npm run build first.");
+ }
+
+ const codeArchiveData = await createCodeArchiveBuffer();
+ const codeArchiveId = await uploader.upload(codeArchiveData, [
+ ["Content-Type", "application/gzip"],
+ ["Content-Encoding", "gzip"],
+ ["App-Name", appName],
+ ["App-Version", appVersion],
+ ["Type", "code-archive"]
+ ]);
+ console.log(`Uploaded code archive: ${codeArchiveId}`);
+
+ const pathMap = {};
+ let indexTxId = "";
+
+ for (const absolutePath of filePaths) {
+ const relativePath = path.relative(distDir, absolutePath).replace(/\\/g, "/");
+ const contentType = mime.lookup(relativePath) || "application/octet-stream";
+ const data = await fs.readFile(absolutePath);
+
+ const txId = await uploader.upload(data, [
+ ["Content-Type", String(contentType)],
+ ["App-Name", appName],
+ ["App-Version", appVersion],
+ ["Type", "app-asset"],
+ ["File-Path", relativePath],
+ ["code", codeArchiveId]
+ ]);
+
+ pathMap[relativePath] = { id: txId };
+ if (relativePath === "index.html") indexTxId = txId;
+ console.log(`Uploaded ${relativePath}: ${txId}`);
+ }
+
+ if (!indexTxId) {
+ throw new Error("Could not find uploaded index.html. Dist output is invalid for SPA deploy.");
+ }
+
+ const slugs = await resolvePostSlugs(gateway);
+ for (const slug of slugs) {
+ pathMap[slug] = { id: indexTxId };
+ pathMap[`${slug}/`] = { id: indexTxId };
+ }
+
+ const manifest = {
+ manifest: "arweave/paths",
+ version: "0.2.0",
+ index: { path: "index.html" },
+ paths: pathMap
+ };
+
+ const manifestId = await uploader.upload(JSON.stringify(manifest), [
+ ["Content-Type", "application/x.arweave-manifest+json"],
+ ["App-Name", appName],
+ ["App-Version", appVersion],
+ ["Type", "manifest"],
+ ["code", codeArchiveId]
+ ]);
+
+ const appUrl = `${gateway.replace(/\/+$/, "")}/${manifestId}/`;
+ const codeArchiveUrl = `${gateway.replace(/\/+$/, "")}/${codeArchiveId}`;
+
+ console.log("");
+ console.log(`Code Archive ID: ${codeArchiveId}`);
+ console.log(`Code Archive URL: ${codeArchiveUrl}`);
+ console.log(`Manifest ID (AppArweaveID): ${manifestId}`);
+ console.log(`App URL: ${appUrl}`);
+ if (slugs.length) {
+ console.log(`Slug route aliases: ${slugs.join(", ")}`);
+ } else {
+ console.log("Slug route aliases: none generated.");
+ }
+}
+
+main().catch((error) => {
+ console.error(error?.message || String(error));
+ process.exit(1);
+});
diff --git a/scripts/generate-wallet.mjs b/scripts/generate-wallet.mjs
new file mode 100644
index 0000000..025d80e
--- /dev/null
+++ b/scripts/generate-wallet.mjs
@@ -0,0 +1,25 @@
+import fs from "node:fs/promises";
+import path from "node:path";
+import Arweave from "arweave";
+
+const root = process.cwd();
+const walletPath = path.join(root, "wallet.json");
+
+async function main() {
+ const arweave = Arweave.init({
+ host: "arweave.net",
+ port: 443,
+ protocol: "https",
+ timeout: 30_000,
+ logging: false
+ });
+
+ const jwk = await arweave.wallets.generate();
+ await fs.writeFile(walletPath, `${JSON.stringify(jwk, null, 2)}\n`, "utf8");
+ console.log(`Generated wallet: ${walletPath}`);
+}
+
+main().catch((error) => {
+ console.error(error?.message || String(error));
+ process.exit(1);
+});
diff --git a/scripts/ship.mjs b/scripts/ship.mjs
new file mode 100644
index 0000000..2aae81b
--- /dev/null
+++ b/scripts/ship.mjs
@@ -0,0 +1,100 @@
+import fs from "node:fs/promises";
+import path from "node:path";
+import { spawn } from "node:child_process";
+
+const root = process.cwd();
+const nodeModulesPath = path.join(root, "node_modules");
+const walletPath = path.join(root, "wallet.json");
+
+async function pathExists(targetPath) {
+ try {
+ await fs.access(targetPath);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+function runCommand(command, args) {
+ return new Promise((resolve, reject) => {
+ const child = spawn(command, args, {
+ cwd: root,
+ stdio: ["ignore", "pipe", "pipe"]
+ });
+
+ let stdout = "";
+ let stderr = "";
+
+ child.stdout.on("data", (chunk) => {
+ const text = chunk.toString();
+ stdout += text;
+ process.stdout.write(text);
+ });
+
+ child.stderr.on("data", (chunk) => {
+ const text = chunk.toString();
+ stderr += text;
+ process.stderr.write(text);
+ });
+
+ child.on("error", reject);
+ child.on("close", (code) => {
+ if (code !== 0) {
+ reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
+ return;
+ }
+ resolve({ stdout, stderr });
+ });
+ });
+}
+
+function extractLink(output, label) {
+ const regex = new RegExp(`${label}:\\s*(https?:\\/\\/\\S+)`);
+ const match = output.match(regex);
+ return match?.[1] || "";
+}
+
+async function ensureDependencies() {
+ if (await pathExists(nodeModulesPath)) {
+ console.log("Dependencies present: skipping npm install.");
+ return;
+ }
+ console.log("Dependencies missing: running npm install...");
+ await runCommand("npm", ["install"]);
+}
+
+async function ensureWallet() {
+ if (await pathExists(walletPath)) {
+ console.log("wallet.json present: skipping wallet:new.");
+ return;
+ }
+ console.log("wallet.json missing: running npm run wallet:new...");
+ await runCommand("npm", ["run", "wallet:new"]);
+}
+
+async function main() {
+ await ensureDependencies();
+ await ensureWallet();
+
+ console.log("Running deploy pipeline: npm run deploy:up");
+ const deployResult = await runCommand("npm", ["run", "deploy:up"]);
+
+ const appUrl = extractLink(deployResult.stdout, "App URL");
+ const codeArchiveUrl = extractLink(deployResult.stdout, "Code Archive URL");
+
+ if (!appUrl || !codeArchiveUrl) {
+ throw new Error(
+ "Deploy step did not emit required links (App URL and Code Archive URL)."
+ );
+ }
+
+ console.log("");
+ console.log("Ship completed.");
+ console.log(`App URL: ${appUrl}`);
+ console.log(`Code Archive URL: ${codeArchiveUrl}`);
+}
+
+main().catch((error) => {
+ console.error(error?.message || String(error));
+ process.exit(1);
+});
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 0000000..774da0c
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,248 @@
+import { useEffect, useMemo, useState } from "react";
+import { Link, Navigate, Route, Routes, useParams } from "react-router-dom";
+import { BLOG_NAME } from "./config";
+import { arweaveUrl, getReadableDate, loadManifest, loadPostContent } from "./lib";
+import type { Frontmatter, ManifestPost } from "./types";
+
+type LoadState = "idle" | "loading" | "error";
+
+function BlisterLoader() {
+ return (
+
+
+
+ );
+}
+
+function App() {
+ const [posts, setPosts] = useState([]);
+ const [state, setState] = useState("idle");
+ const [error, setError] = useState("");
+
+ useEffect(() => {
+ let ignore = false;
+
+ const run = async () => {
+ try {
+ setState("loading");
+ const data = await loadManifest();
+ if (!ignore) {
+ setPosts(
+ [...data].sort((a, b) => {
+ const aDate = a.publishedAt ?? "";
+ const bDate = b.publishedAt ?? "";
+ return aDate < bDate ? 1 : -1;
+ })
+ );
+ setState("idle");
+ }
+ } catch (err) {
+ if (!ignore) {
+ setError(err instanceof Error ? err.message : "Failed to load manifest");
+ setState("error");
+ }
+ }
+ };
+
+ void run();
+ return () => {
+ ignore = true;
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ {BLOG_NAME}
+
+
+
+
+ }
+ />
+ }
+ />
+ } />
+
+
+
+ );
+}
+
+function IndexPage({
+ posts,
+ state,
+ error
+}: {
+ posts: ManifestPost[];
+ state: LoadState;
+ error: string;
+}) {
+ if (state === "loading") return ;
+ if (state === "error") return Error: {error}
;
+ if (posts.length === 0) return No posts yet.
;
+
+ const hasFeatured = posts.length >= 3;
+ const featuredPost = hasFeatured ? posts[0] : null;
+ const gridPosts = hasFeatured ? posts.slice(1) : posts;
+
+ const renderPost = (post: ManifestPost) => {
+ const publishedDate = getReadableDate(post.publishedAt);
+ const bannerTxId = post.frontmatter?.banner ?? post.bannerTxId;
+
+ return (
+ <>
+ {bannerTxId && (
+
+
+
+ )}
+
+ {post.title}
+
+
+ {post.description || post.excerpt || "No description provided."}
+
+
+ {publishedDate && {publishedDate} }
+ {post.readingTime && {post.readingTime} min read }
+ {post.wordCount && {post.wordCount} words }
+
+ >
+ );
+ };
+
+ return (
+
+ {featuredPost && (
+
+ {renderPost(featuredPost)}
+
+ )}
+
+ {gridPosts.map((post) => (
+
+ {renderPost(post)}
+
+ ))}
+
+
+ );
+}
+
+function PostPage({
+ posts,
+ state,
+ manifestError
+}: {
+ posts: ManifestPost[];
+ state: LoadState;
+ manifestError: string;
+}) {
+ const { slug = "" } = useParams();
+ const post = useMemo(() => posts.find((entry) => entry.slug === slug), [posts, slug]);
+ const [html, setHtml] = useState("");
+ const [postFrontmatter, setPostFrontmatter] = useState({});
+ const [postState, setPostState] = useState("idle");
+ const [postError, setPostError] = useState("");
+ const [showPostLoader, setShowPostLoader] = useState(false);
+
+ useEffect(() => {
+ if (postState !== "loading") {
+ setShowPostLoader(false);
+ return;
+ }
+
+ const timeout = window.setTimeout(() => setShowPostLoader(true), 300);
+ return () => window.clearTimeout(timeout);
+ }, [postState]);
+
+ useEffect(() => {
+ let ignore = false;
+ if (!post) return;
+
+ const run = async () => {
+ try {
+ setPostError("");
+ setPostState("loading");
+ const { html: nextHtml, frontmatter } = await loadPostContent(post.postTxId);
+ if (!ignore) {
+ setHtml(nextHtml);
+ setPostFrontmatter(frontmatter);
+ setPostState("idle");
+ }
+ } catch (err) {
+ if (!ignore) {
+ setPostError(err instanceof Error ? err.message : "Failed to load post");
+ setPostState("error");
+ }
+ }
+ };
+
+ void run();
+ return () => {
+ ignore = true;
+ };
+ }, [post]);
+
+ if (state === "loading") return ;
+ if (state === "error") return Error: {manifestError}
;
+ if (!post) return Post not found.
;
+ if (postState === "loading") return showPostLoader ? : null;
+ if (postState === "error") return Error: {postError}
;
+
+ const title = postFrontmatter.title || post.title;
+ const description =
+ postFrontmatter.desc ||
+ postFrontmatter.description ||
+ post.description ||
+ postFrontmatter.excerpt ||
+ post.excerpt ||
+ "";
+ const bannerTxId = postFrontmatter.banner || post.frontmatter?.banner || post.bannerTxId;
+ const publishedDate = getReadableDate(postFrontmatter.date || post.publishedAt);
+ const updatedDate = getReadableDate(postFrontmatter.updated || post.updated || undefined);
+
+ return (
+
+
+ {bannerTxId && (
+
+
+
+ )}
+
+
+ );
+}
+
+export default App;
diff --git a/src/config.ts b/src/config.ts
new file mode 100644
index 0000000..f852d56
--- /dev/null
+++ b/src/config.ts
@@ -0,0 +1,6 @@
+export const BLOG_NAME = "hyperzine";
+export const MANIFEST_TX_ID = "Zjc1hce_CgyNrq7qqufrJ20ra7IvNU7t8EnK2QA1EHE";
+export const ARWEAVE_GATEWAY = "https://arweave.net";
+
+export const AO_URL = "https://push-1.forward.computer";
+export const AO_PROCESS_ID = "fiZ72JP4b6vOuy9PGzqTJo3JLG_LJRmjfZoI6z8E3n4";
diff --git a/src/lib.ts b/src/lib.ts
new file mode 100644
index 0000000..49950b1
--- /dev/null
+++ b/src/lib.ts
@@ -0,0 +1,185 @@
+import DOMPurify from "dompurify";
+import { marked } from "marked";
+import { parse as parseYaml } from "yaml";
+import {
+ AO_PROCESS_ID,
+ AO_URL,
+ ARWEAVE_GATEWAY,
+ MANIFEST_TX_ID
+} from "./config";
+import { parseManifest, type Frontmatter, type ManifestPost } from "./types";
+
+const formatDate = (date: string): string =>
+ new Date(date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric"
+ });
+
+marked.setOptions({
+ gfm: true,
+ breaks: false
+});
+
+export const arweaveUrl = (txId: string): string => `${ARWEAVE_GATEWAY}/${txId}`;
+
+export const getReadableDate = (date?: string | null): string | null => {
+ if (!date) return null;
+ const parsed = Date.parse(date);
+ if (Number.isNaN(parsed)) return null;
+ return formatDate(date);
+};
+
+const asObject = (value: unknown): Record | null =>
+ typeof value === "object" && value !== null ? (value as Record) : null;
+
+const asString = (value: unknown): string | null =>
+ typeof value === "string" && value.length > 0 ? value : null;
+
+const getLatestManifestFromAo = async (): Promise => {
+ try {
+ const pushResponse = await fetch(`${AO_URL}/${AO_PROCESS_ID}~process@1.0/push`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ "signing-format": "ans104",
+ "accept-bundle": "true",
+ "require-codec": "application/json"
+ },
+ body: JSON.stringify({
+ Type: "Message",
+ "Data-Protocol": "ao",
+ Variant: "ao.N.1",
+ Action: "Get",
+ target: AO_PROCESS_ID,
+ data: "1984"
+ })
+ });
+ if (!pushResponse.ok) return null;
+
+ const pushPayload = (await pushResponse.json()) as unknown;
+ const slot = asString(asObject(pushPayload)?.slot);
+ if (!slot) return null;
+
+ const computeResponse = await fetch(`${AO_URL}/${AO_PROCESS_ID}~process@1.0/compute=${slot}`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ "signing-format": "ans104",
+ "accept-bundle": "true",
+ "require-codec": "application/json"
+ },
+ body: JSON.stringify({
+ target: AO_PROCESS_ID,
+ data: "1984"
+ })
+ });
+ if (!computeResponse.ok) return null;
+
+ const computePayload = (await computeResponse.json()) as unknown;
+ const body = asObject(asObject(asObject(computePayload)?.results)?.json)?.body;
+ const parsedBody = typeof body === "string" ? asObject(JSON.parse(body)) : asObject(body);
+ const messages = Array.isArray(parsedBody?.Messages) ? parsedBody.Messages : [];
+
+ for (const message of messages) {
+ const tags = Array.isArray(asObject(message)?.Tags) ? (asObject(message)?.Tags as unknown[]) : [];
+ for (const tag of tags) {
+ const tagObject = asObject(tag);
+ const name = asString(tagObject?.name) ?? asString(tagObject?.Name);
+ const value = asString(tagObject?.value) ?? asString(tagObject?.Value);
+ if (name === "LatestManifestId" && value) return value;
+ }
+ }
+
+ return null;
+ } catch {
+ return null;
+ }
+};
+
+export const loadManifest = async (): Promise => {
+ const manifestTxId = (await getLatestManifestFromAo()) ?? MANIFEST_TX_ID;
+ const response = await fetch(arweaveUrl(manifestTxId));
+ if (!response.ok) {
+ throw new Error(`Failed to load manifest (${response.status})`);
+ }
+
+ const payload: unknown = await response.json();
+ return parseManifest(payload);
+};
+
+const isObject = (value: unknown): value is Record =>
+ typeof value === "object" && value !== null;
+
+const asStringOrUndefined = (value: unknown): string | undefined =>
+ typeof value === "string" ? value : undefined;
+
+const asBannerTxId = (value: unknown): string | undefined => {
+ if (typeof value === "string") return value;
+ if (!isObject(value)) return undefined;
+ return (
+ asStringOrUndefined(value.txId) ??
+ asStringOrUndefined(value.id) ??
+ asStringOrUndefined(value.src) ??
+ asStringOrUndefined(value.url)
+ );
+};
+
+const asStringArray = (value: unknown): string[] =>
+ Array.isArray(value)
+ ? value.filter((entry): entry is string => typeof entry === "string")
+ : [];
+
+const parseFrontmatter = (input: unknown): Frontmatter => {
+ if (!isObject(input)) return {};
+ return {
+ title: asStringOrUndefined(input.title),
+ desc: asStringOrUndefined(input.desc),
+ description: asStringOrUndefined(input.description),
+ excerpt: asStringOrUndefined(input.excerpt),
+ slug: asStringOrUndefined(input.slug),
+ banner: asBannerTxId(input.banner),
+ date: asStringOrUndefined(input.date),
+ updated: asStringOrUndefined(input.updated),
+ tags: asStringArray(input.tags),
+ categories: asStringArray(input.categories)
+ };
+};
+
+export interface PostContent {
+ html: string;
+ frontmatter: Frontmatter;
+}
+
+const FRONTMATTER_PATTERN = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/;
+
+const splitFrontmatter = (
+ markdown: string
+): { frontmatter: Frontmatter; content: string } => {
+ const match = markdown.match(FRONTMATTER_PATTERN);
+ if (!match) {
+ return { frontmatter: {}, content: markdown };
+ }
+
+ const parsed = parseYaml(match[1]);
+ const frontmatter = parseFrontmatter(parsed);
+ return {
+ frontmatter,
+ content: markdown.slice(match[0].length)
+ };
+};
+
+export const loadPostContent = async (txId: string): Promise => {
+ const response = await fetch(arweaveUrl(txId));
+ if (!response.ok) {
+ throw new Error(`Failed to load post (${response.status})`);
+ }
+
+ const markdown = await response.text();
+ const { frontmatter, content } = splitFrontmatter(markdown);
+ const html = await marked.parse(content);
+ return {
+ html: DOMPurify.sanitize(html),
+ frontmatter
+ };
+};
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 0000000..5e74ac7
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,13 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { BrowserRouter } from "react-router-dom";
+import App from "./App";
+import "./styles.css";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+
+
+
+);
diff --git a/src/styles.css b/src/styles.css
new file mode 100644
index 0000000..4421d7f
--- /dev/null
+++ b/src/styles.css
@@ -0,0 +1,303 @@
+:root {
+ color: #0a0a0a;
+ background: #ffffff;
+ font-family: "IBM Plex Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ line-height: 1.6;
+ --brand-red: #f60000;
+ --brand-purple: #9611ff;
+ --brand-blue: #86dafe;
+ --brand-yellow: #fee55f;
+ --brand-green: #33f22f;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ background: #ffffff;
+ color: #111111;
+}
+
+a {
+ color: #111111;
+ text-decoration-thickness: 1px;
+ text-underline-offset: 3px;
+}
+
+.page {
+ min-height: 100vh;
+ padding: 24px;
+}
+
+.header {
+ border-bottom: 2px solid #111111;
+ padding-bottom: 14px;
+ margin-bottom: 28px;
+}
+
+.brand {
+ font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
+ font-size: 1.3rem;
+ font-weight: 600;
+ letter-spacing: 0.08em;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.brand-mark {
+ display: inline-flex;
+ gap: 1px;
+ transform: translateY(2px);
+}
+
+.brand-text {
+ display: inline-block;
+ transform: rotate(-3deg);
+ transform-origin: left center;
+}
+
+.brand-square {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+}
+
+.brand-square-red {
+ background: var(--brand-red);
+}
+
+.brand-square-purple {
+ background: var(--brand-purple);
+}
+
+.brand-square-blue {
+ background: var(--brand-blue);
+}
+
+.brand-square-yellow {
+ background: var(--brand-yellow);
+}
+
+.brand-square-green {
+ background: var(--brand-green);
+}
+
+.content {
+ max-width: 860px;
+ margin: 0 auto;
+}
+
+.status {
+ font-size: 1rem;
+}
+
+.loader-screen {
+ min-height: calc(100vh - 160px);
+ display: grid;
+ place-items: center;
+}
+
+.loader-square {
+ width: 22px;
+ height: 22px;
+ background: var(--brand-red);
+ animation: blister-flicker 180ms steps(1, end) infinite;
+}
+
+@keyframes blister-flicker {
+ 0% {
+ background: var(--brand-red);
+ }
+ 20% {
+ background: var(--brand-purple);
+ }
+ 40% {
+ background: var(--brand-blue);
+ }
+ 60% {
+ background: var(--brand-yellow);
+ }
+ 80% {
+ background: var(--brand-green);
+ }
+ 100% {
+ background: var(--brand-red);
+ }
+}
+
+.index {
+ display: grid;
+ gap: 28px;
+}
+
+.index-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ column-gap: 28px;
+ row-gap: 28px;
+}
+
+.post-card {
+ padding-top: 0;
+}
+
+.index-grid .post-card:nth-child(n + 3) {
+ border-top: 1px solid #111111;
+ padding-top: 18px;
+}
+
+.post-card-featured {
+ border-top: 0;
+ padding-top: 0;
+}
+
+.banner-link {
+ display: block;
+ margin-bottom: 14px;
+}
+
+.post-banner {
+ display: block;
+ width: 100%;
+ height: auto;
+ border: 1px solid #111111;
+}
+
+.post-title-link {
+ text-decoration: none;
+}
+
+.post-title {
+ margin: 0;
+ font-size: 1.8rem;
+ line-height: 1.2;
+}
+
+.post-description {
+ margin: 10px 0 12px;
+ font-size: 1.04rem;
+}
+
+.meta-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0;
+ font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
+ font-size: 0.86rem;
+}
+
+.meta-row > span + span {
+ position: relative;
+ margin-left: 14px;
+ padding-left: 14px;
+}
+
+.meta-row > span + span::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ width: 6px;
+ height: 1px;
+ background: #111111;
+ transform: translateY(-50%);
+}
+
+.post {
+ max-width: 760px;
+}
+
+.post-topline {
+ margin-bottom: 16px;
+}
+
+.home-link {
+ text-decoration: none;
+ border-bottom: 1px solid #111111;
+}
+
+.post-header h1 {
+ margin: 0;
+ line-height: 1.15;
+ font-size: clamp(2rem, 6vw, 3.4rem);
+}
+
+.post-header p {
+ margin: 12px 0;
+ font-size: 1.06rem;
+}
+
+.post-hero {
+ margin-top: 24px;
+}
+
+.article {
+ margin-top: 32px;
+ border-top: 1px solid #111111;
+ padding-top: 24px;
+}
+
+.article > *:first-child {
+ margin-top: 0;
+}
+
+.article h2,
+.article h3,
+.article h4 {
+ margin-top: 1.9em;
+ line-height: 1.25;
+}
+
+.article pre {
+ border: 1px solid #111111;
+ padding: 14px;
+ overflow: auto;
+ background: #ffffff;
+}
+
+.article code {
+ font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
+}
+
+.article blockquote {
+ margin-left: 0;
+ padding-left: 16px;
+ border-left: 2px solid #111111;
+}
+
+.article img {
+ max-width: 100%;
+ height: auto;
+}
+
+@media (max-width: 740px) {
+ .page {
+ padding: 16px;
+ }
+
+ .index {
+ grid-template-columns: 1fr;
+ }
+
+ .index-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .index-grid .post-card:nth-child(n + 3) {
+ border-top: 0;
+ padding-top: 0;
+ }
+
+ .index-grid .post-card + .post-card {
+ border-top: 1px solid #111111;
+ padding-top: 18px;
+ }
+
+ .post-title {
+ font-size: 1.45rem;
+ }
+}
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..883f265
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,110 @@
+export interface Frontmatter {
+ title?: string;
+ desc?: string;
+ description?: string;
+ excerpt?: string;
+ slug?: string;
+ banner?: string;
+ date?: string;
+ updated?: string;
+ tags?: string[];
+ categories?: string[];
+}
+
+export interface ManifestPost {
+ slug: string;
+ title: string;
+ description: string;
+ excerpt?: string;
+ postTxId: string;
+ bannerTxId?: string;
+ publishedAt?: string;
+ updated?: string | null;
+ readingTime?: number;
+ wordCount?: number;
+ tags?: string[];
+ categories?: string[];
+ frontmatter?: Frontmatter;
+}
+
+interface ManifestResponse {
+ posts?: ManifestPost[];
+}
+
+const isObject = (value: unknown): value is Record =>
+ typeof value === "object" && value !== null;
+
+const asString = (value: unknown): string | undefined =>
+ typeof value === "string" ? value : undefined;
+
+const asBannerTxId = (value: unknown): string | undefined => {
+ if (typeof value === "string") return value;
+ if (!isObject(value)) return undefined;
+ return (
+ asString(value.txId) ??
+ asString(value.id) ??
+ asString(value.src) ??
+ asString(value.url)
+ );
+};
+
+const asStringArray = (value: unknown): string[] =>
+ Array.isArray(value)
+ ? value.filter((entry): entry is string => typeof entry === "string")
+ : [];
+
+const toFrontmatter = (value: unknown): Frontmatter | undefined => {
+ if (!isObject(value)) return undefined;
+ return {
+ title: asString(value.title),
+ desc: asString(value.desc),
+ description: asString(value.description),
+ excerpt: asString(value.excerpt),
+ slug: asString(value.slug),
+ banner: asBannerTxId(value.banner),
+ date: asString(value.date),
+ updated: asString(value.updated),
+ tags: asStringArray(value.tags),
+ categories: asStringArray(value.categories)
+ };
+};
+
+const toPost = (input: unknown): ManifestPost | null => {
+ if (!isObject(input)) return null;
+
+ const frontmatter = toFrontmatter(input.frontmatter);
+ const slug = asString(input.slug) ?? frontmatter?.slug;
+ const title = asString(input.title) ?? frontmatter?.title ?? "Untitled";
+ const postTxId = asString(input.postTxId);
+ if (!slug || !postTxId) return null;
+
+ return {
+ slug,
+ title,
+ description:
+ asString(input.description) ??
+ frontmatter?.desc ??
+ frontmatter?.description ??
+ "",
+ excerpt: asString(input.excerpt) ?? frontmatter?.excerpt,
+ postTxId,
+ bannerTxId: asBannerTxId(input.bannerTxId) ?? frontmatter?.banner,
+ publishedAt: asString(input.publishedAt) ?? frontmatter?.date,
+ updated: asString(input.updated) ?? frontmatter?.updated,
+ readingTime:
+ typeof input.readingTime === "number" ? input.readingTime : undefined,
+ wordCount: typeof input.wordCount === "number" ? input.wordCount : undefined,
+ tags: asStringArray(input.tags).length ? asStringArray(input.tags) : frontmatter?.tags ?? [],
+ categories: asStringArray(input.categories).length
+ ? asStringArray(input.categories)
+ : frontmatter?.categories ?? [],
+ frontmatter
+ };
+};
+
+export const parseManifest = (input: unknown): ManifestPost[] => {
+ if (!isObject(input)) return [];
+ const { posts } = input as ManifestResponse;
+ if (!Array.isArray(posts)) return [];
+ return posts.map(toPost).filter((post): post is ManifestPost => post !== null);
+};
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000..0426f7b
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..1ffef60
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..97ede7e
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/vite.config.d.ts b/vite.config.d.ts
new file mode 100644
index 0000000..340562a
--- /dev/null
+++ b/vite.config.d.ts
@@ -0,0 +1,2 @@
+declare const _default: import("vite").UserConfig;
+export default _default;
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..04d7917
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,6 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+export default defineConfig({
+ base: "./",
+ plugins: [react()]
+});
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..3de48b9
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+export default defineConfig({
+ base: "./",
+ plugins: [react()]
+});