diff --git a/.claude/launch.json b/.claude/launch.json
new file mode 100644
index 0000000..f612a0a
--- /dev/null
+++ b/.claude/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.0.1",
+ "configurations": [
+ {
+ "name": "rose-dev",
+ "runtimeExecutable": "npm",
+ "runtimeArgs": ["run", "dev"],
+ "port": 3000
+ }
+ ]
+}
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..8d886db
--- /dev/null
+++ b/components.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "base-nova",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "iconLibrary": "lucide",
+ "rtl": false,
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "menuColor": "default",
+ "menuAccent": "subtle",
+ "registries": {}
+}
diff --git a/package-lock.json b/package-lock.json
index 522c163..6c6bbd7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,18 @@
"name": "rose",
"version": "0.1.0",
"dependencies": {
+ "@base-ui/react": "^1.7.0",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^1.28.0",
"next": "16.3.0",
+ "next-themes": "^0.4.6",
"react": "19.2.8",
- "react-dom": "19.2.8"
+ "react-dom": "19.2.8",
+ "shadcn": "^4.16.1",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.6.0",
+ "tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
@@ -40,7 +49,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.29.7",
@@ -55,7 +63,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -65,7 +72,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -96,7 +102,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
"integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.8",
@@ -109,11 +114,22 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz",
+ "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-compilation-targets": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.29.7",
@@ -126,21 +142,53 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz",
+ "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/helper-replace-supers": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
"node_modules/@babel/helper-globals": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz",
+ "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-module-imports": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.29.7",
@@ -154,7 +202,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.29.7",
@@ -168,11 +215,61 @@
"@babel/core": "^7.0.0"
}
},
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz",
+ "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz",
+ "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz",
+ "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -182,7 +279,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -192,7 +288,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -202,7 +297,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.29.7",
@@ -216,7 +310,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
"integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.8"
@@ -228,11 +321,103 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz",
+ "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz",
+ "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz",
+ "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/plugin-syntax-typescript": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz",
+ "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "@babel/plugin-syntax-jsx": "^7.29.7",
+ "@babel/plugin-transform-modules-commonjs": "^7.29.7",
+ "@babel/plugin-transform-typescript": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
+ "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -247,7 +432,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
"integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -266,7 +450,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
"integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.29.7",
@@ -276,6 +459,300 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@base-ui/react": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.7.0.tgz",
+ "integrity": "sha512-j+8QjX44C32jrXD/qyEAGpFr70FRpGL2CY61mQd9nBPWN737CK0xxD1ceJ055rW4RtdvFDT1e7otzdlfxvsYug==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.29.2",
+ "@base-ui/utils": "0.3.2",
+ "@floating-ui/react-dom": "^2.1.9",
+ "@floating-ui/utils": "^0.2.12",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@date-fns/tz": "^1.2.0",
+ "@types/react": "^17 || ^18 || ^19",
+ "date-fns": "^4.0.0",
+ "react": "^17 || ^18 || ^19",
+ "react-dom": "^17 || ^18 || ^19"
+ },
+ "peerDependenciesMeta": {
+ "@date-fns/tz": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@base-ui/utils": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.3.2.tgz",
+ "integrity": "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.29.2",
+ "@floating-ui/utils": "^0.2.12",
+ "reselect": "^5.2.0",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^17 || ^18 || ^19",
+ "react": "^17 || ^18 || ^19",
+ "react-dom": "^17 || ^18 || ^19"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@dotenvx/dotenvx": {
+ "version": "1.75.1",
+ "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz",
+ "integrity": "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@dotenvx/primitives": "^0.8.0",
+ "commander": "^11.1.0",
+ "conf": "^10.2.0",
+ "dotenv": "^17.2.1",
+ "enquirer": "^2.4.1",
+ "env-paths": "^2.2.1",
+ "execa": "^5.1.1",
+ "fdir": "^6.2.0",
+ "ignore": "^5.3.0",
+ "object-treeify": "1.1.33",
+ "open": "^8.4.2",
+ "picomatch": "^4.0.4",
+ "systeminformation": "^5.22.11",
+ "undici": "^7.11.0",
+ "which": "^4.0.0",
+ "yocto-spinner": "^1.1.0"
+ },
+ "bin": {
+ "dotenvx": "src/cli/dotenvx.js"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/isexe": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz",
+ "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@dotenvx/dotenvx/node_modules/which": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
+ "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^3.1.1"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@dotenvx/primitives": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@dotenvx/primitives/-/primitives-0.8.0.tgz",
+ "integrity": "sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -453,6 +930,56 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+ "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+ "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.8.0",
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz",
+ "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.8.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
+ "license": "MIT"
+ },
+ "node_modules/@hono/node-server": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.0.tgz",
+ "integrity": "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "hono": "^4"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
@@ -1072,7 +1599,6 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@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",
@@ -1083,7 +1609,6 @@
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -1094,7 +1619,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -1104,20 +1628,80 @@
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@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.npmjs.org/@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/@modelcontextprotocol/sdk": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz",
+ "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==",
+ "license": "MIT",
+ "dependencies": {
+ "@hono/node-server": "^1.19.9 || ^2.0.5",
+ "ajv": "^8.17.1",
+ "ajv-formats": "^3.0.1",
+ "content-type": "^1.0.5",
+ "cors": "^2.8.5",
+ "cross-spawn": "^7.0.5",
+ "eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
+ "express": "^5.2.1",
+ "express-rate-limit": "^8.2.1",
+ "hono": "^4.11.4",
+ "jose": "^6.1.3",
+ "json-schema-typed": "^8.0.2",
+ "pkce-challenge": "^5.0.0",
+ "raw-body": "^3.0.0",
+ "zod": "^3.25 || ^4.0",
+ "zod-to-json-schema": "^3.25.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@cfworker/json-schema": "^4.1.1",
+ "zod": "^3.25 || ^4.0"
+ },
+ "peerDependenciesMeta": {
+ "@cfworker/json-schema": {
+ "optional": true
+ },
+ "zod": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz",
@@ -1333,7 +1917,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
@@ -1347,7 +1930,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -1357,7 +1939,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
@@ -1384,6 +1965,24 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "license": "MIT"
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1676,6 +2275,81 @@
"tailwindcss": "4.3.3"
}
},
+ "node_modules/@ts-morph/common": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz",
+ "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-glob": "^3.3.3",
+ "minimatch": "^10.0.1",
+ "path-browserify": "^1.0.1"
+ }
+ },
+ "node_modules/@ts-morph/common/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@ts-morph/common/node_modules/brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@ts-morph/common/node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/@ts-morph/common/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@ts-morph/common/node_modules/minimatch": {
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.8"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@tybys/wasm-util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
@@ -1722,7 +2396,7 @@
"version": "19.2.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
"integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -1738,6 +2412,12 @@
"@types/react": "^19.2.0"
}
},
+ "node_modules/@types/validate-npm-package-name": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz",
+ "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==",
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.66.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz",
@@ -2387,6 +3067,19 @@
"win32"
]
},
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/acorn": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
@@ -2427,6 +3120,63 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -2447,7 +3197,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
"license": "Python-2.0"
},
"node_modules/aria-query": {
@@ -2620,6 +3369,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/ast-types": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz",
+ "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/ast-types-flow": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
@@ -2637,6 +3398,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/atomically": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
+ "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.12.0"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -2692,6 +3462,43 @@
"node": ">=6.0.0"
}
},
+ "node_modules/body-parser": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
+ "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^2.0.0",
+ "debug": "^4.4.3",
+ "http-errors": "^2.0.1",
+ "iconv-lite": "^0.7.2",
+ "on-finished": "^2.4.1",
+ "qs": "^6.15.2",
+ "raw-body": "^3.0.2",
+ "type-is": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/body-parser/node_modules/content-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
+ "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
@@ -2707,7 +3514,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -2720,7 +3526,6 @@
"version": "4.28.7",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
"integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2750,6 +3555,30 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
@@ -2773,7 +3602,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -2787,7 +3615,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -2804,7 +3631,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -2847,12 +3673,66 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/code-block-writer": {
+ "version": "13.0.3",
+ "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz",
+ "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==",
+ "license": "MIT"
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2873,6 +3753,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/commander": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
+ "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2880,18 +3769,180 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/conf": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz",
+ "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.6.3",
+ "ajv-formats": "^2.1.1",
+ "atomically": "^1.7.0",
+ "debounce-fn": "^4.0.0",
+ "dot-prop": "^6.0.1",
+ "env-paths": "^2.2.1",
+ "json-schema-typed": "^7.0.3",
+ "onetime": "^5.1.2",
+ "pkg-up": "^3.1.0",
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/conf/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/conf/node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/conf/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/conf/node_modules/json-schema-typed": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
+ "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/conf/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
+ "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
+ "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz",
+ "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==",
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -2902,11 +3953,23 @@
"node": ">= 8"
}
},
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -2970,11 +4033,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/debounce-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
+ "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2988,6 +4065,20 @@
}
}
},
+ "node_modules/dedent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz",
+ "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -2995,6 +4086,43 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/default-browser": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz",
+ "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
+ "license": "MIT",
+ "dependencies": {
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+ "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -3013,6 +4141,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
@@ -3031,6 +4171,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -3041,6 +4190,15 @@
"node": ">=8"
}
},
+ "node_modules/diff": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -3054,11 +4212,37 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dot-prop": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
+ "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "17.4.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
+ "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -3069,11 +4253,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.400",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz",
"integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==",
- "dev": true,
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -3083,6 +4272,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.24.5",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
@@ -3097,6 +4295,37 @@
"node": ">=10.13.0"
}
},
+ "node_modules/enquirer": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.24.2",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
@@ -3189,7 +4418,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -3199,7 +4427,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -3237,7 +4464,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -3300,12 +4526,17 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -3679,6 +4910,19 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esquery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
@@ -3725,11 +4969,128 @@
"node": ">=0.10.0"
}
},
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventsource": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
+ "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
+ "license": "MIT",
+ "dependencies": {
+ "eventsource-parser": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/eventsource-parser": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz",
+ "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
+ "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "figures": "^6.1.0",
+ "get-stream": "^9.0.0",
+ "human-signals": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "is-stream": "^4.0.1",
+ "npm-run-path": "^6.0.0",
+ "pretty-ms": "^9.2.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^4.0.0",
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.5.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
+ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.1",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express-rate-limit": {
+ "version": "8.6.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.1.tgz",
+ "integrity": "sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "ip-address": "^10.2.0"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/express-rate-limit"
+ },
+ "peerDependencies": {
+ "express": ">= 4.11"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -3776,16 +5137,46 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-uri": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
+ "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/fastq": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
- "dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
},
+ "node_modules/figures": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+ "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3803,7 +5194,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -3812,6 +5202,27 @@
"node": ">=8"
}
},
+ "node_modules/finalhandler": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
+ "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -3866,11 +5277,42 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "11.4.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz",
+ "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3910,6 +5352,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/fuzzysort": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz",
+ "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==",
+ "license": "MIT"
+ },
"node_modules/generator-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
@@ -3924,17 +5372,27 @@
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/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/get-east-asian-width": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
+ "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -3955,11 +5413,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-own-enumerable-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz",
+ "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -3969,6 +5438,22 @@
"node": ">= 0.4"
}
},
+ "node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-symbol-description": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
@@ -4047,7 +5532,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4060,7 +5544,6 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/has-bigints": {
@@ -4119,7 +5602,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4148,7 +5630,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -4174,11 +5655,64 @@
"hermes-estree": "0.25.1"
}
},
+ "node_modules/hono": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.0.tgz",
+ "integrity": "sha512-jhunvfHWxd7J5EFfSgH4xsYJzSe/lfqbUCxiyyeaQasUsXeEHXtzVid+7EOGByc5JnFa23SSFL3Y2RV/z1T+eQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
+ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
+ "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
@@ -4188,7 +5722,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
@@ -4211,6 +5744,12 @@
"node": ">=0.8.19"
}
},
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -4226,6 +5765,24 @@
"node": ">= 0.4"
}
},
+ "node_modules/ip-address": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz",
+ "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4244,6 +5801,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
@@ -4384,6 +5947,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-document.all": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz",
@@ -4404,7 +5982,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4450,7 +6027,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -4459,6 +6035,48 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-in-ssh": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz",
+ "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-interactive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
@@ -4489,7 +6107,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -4512,6 +6129,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -4531,6 +6175,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-regexp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz",
+ "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-set": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
@@ -4560,6 +6216,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-string": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
@@ -4611,6 +6279,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
@@ -4657,6 +6337,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-wsl": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+ "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
@@ -4668,7 +6363,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true,
"license": "ISC"
},
"node_modules/iterator.prototype": {
@@ -4699,18 +6393,25 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/jose": {
+ "version": "6.2.8",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.8.tgz",
+ "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -4733,7 +6434,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -4749,6 +6449,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -4756,6 +6462,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-schema-typed": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
+ "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
@@ -4767,7 +6479,6 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
@@ -4776,6 +6487,18 @@
"node": ">=6"
}
},
+ "node_modules/jsonfile": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
+ "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -4802,6 +6525,15 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -5109,6 +6841,12 @@
"url": "https://opencollective.com/parcel"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -5132,6 +6870,46 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/log-symbols": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5149,12 +6927,20 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/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/lucide-react": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.28.0.tgz",
+ "integrity": "sha512-fARAFJULsGuDDydjp6+6blekG/sBIM29TerzLjc9bQUKAcEfrSc4ZQKb25KRz4OMKd87cZTb5dgq0w/T6KufVg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -5169,17 +6955,46 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
+ "node_modules/media-typer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz",
+ "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "license": "MIT"
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -5189,7 +7004,6 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@@ -5199,6 +7013,52 @@
"node": ">=8.6"
}
},
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/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.npmjs.org/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/mimic-fn": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
+ "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
@@ -5216,7 +7076,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -5226,7 +7085,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -5270,6 +7128,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/next": {
"version": "16.3.0",
"resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz",
@@ -5323,6 +7190,16 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+ "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.5.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
@@ -5374,17 +7251,43 @@
"version": "2.0.52",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz",
"integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
+ "node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5394,7 +7297,6 @@
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -5413,6 +7315,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/object-treeify": {
+ "version": "1.1.33",
+ "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz",
+ "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/object.assign": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
@@ -5503,6 +7414,71 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/onetime/node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/open": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz",
+ "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==",
+ "license": "MIT",
+ "dependencies": {
+ "default-browser": "^5.4.0",
+ "define-lazy-prop": "^3.0.0",
+ "is-in-ssh": "^1.0.0",
+ "is-inside-container": "^1.0.0",
+ "powershell-utils": "^0.1.0",
+ "wsl-utils": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5521,6 +7497,68 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ora": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
+ "is-interactive": "^2.0.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/own-keys": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz",
@@ -5572,11 +7610,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
@@ -5585,6 +7631,51 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "license": "MIT"
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -5599,7 +7690,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5612,6 +7702,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-to-regexp": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
+ "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -5622,7 +7722,6 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -5631,6 +7730,88 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pkce-challenge": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz",
+ "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/pkg-up": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
+ "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pkg-up/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-up/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pkg-up/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -5645,7 +7826,6 @@
"version": "8.5.25",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
"integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5670,6 +7850,31 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postcss-selector-parser": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz",
+ "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==",
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/powershell-utils": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
+ "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -5680,6 +7885,43 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/pretty-ms": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
+ "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/prompts/node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5692,6 +7934,19 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5702,11 +7957,26 @@
"node": ">=6"
}
},
+ "node_modules/qs": {
+ "version": "6.15.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
+ "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "es-define-property": "^1.0.1",
+ "side-channel": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5723,6 +7993,34 @@
],
"license": "MIT"
},
+ "node_modules/range-parser": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz",
+ "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
+ "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.7.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/react": {
"version": "19.2.8",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
@@ -5751,6 +8049,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/recast": {
+ "version": "0.23.19",
+ "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.19.tgz",
+ "integrity": "sha512-T98lym7kH+pnZmRaD8yDRdaNqyUbwnbEBx0MuchrzMFOEMray4AO3ZJoTUZ5r78Ao78X/OhzW0DL8GB85w/I2w==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.16.1",
+ "esprima": "~4.0.0",
+ "source-map": "~0.6.1",
+ "tiny-invariant": "^1.3.3",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -5795,6 +8109,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/reselect": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz",
+ "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "2.0.0-next.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz",
@@ -5823,7 +8152,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -5839,22 +8167,79 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
+ "node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/restore-cursor/node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/run-applescript": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+ "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5929,6 +8314,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
@@ -5939,12 +8330,56 @@
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
+ "node_modules/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.1",
+ "mime-types": "^3.0.2",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+ "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -5994,6 +8429,109 @@
"node": ">= 0.4"
}
},
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/shadcn": {
+ "version": "4.16.1",
+ "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.16.1.tgz",
+ "integrity": "sha512-XLFzfNNIUPlUlyheFEzj0H4Vnhi9nI0nl3Nfgg8HYXW1FkUVhVT1X+mgmOUW8aWL5SeG0A+yJIV5fm3Hr9MVkQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/parser": "^7.28.0",
+ "@babel/plugin-transform-typescript": "^7.28.0",
+ "@babel/preset-typescript": "^7.27.1",
+ "@dotenvx/dotenvx": "^1.48.4",
+ "@modelcontextprotocol/sdk": "^1.26.0",
+ "@types/validate-npm-package-name": "^4.0.2",
+ "browserslist": "^4.26.2",
+ "commander": "^14.0.0",
+ "cosmiconfig": "^9.0.0",
+ "dedent": "^1.6.0",
+ "deepmerge": "^4.3.1",
+ "diff": "^8.0.2",
+ "execa": "^9.6.0",
+ "fast-glob": "^3.3.3",
+ "fs-extra": "^11.3.1",
+ "fuzzysort": "^3.1.0",
+ "kleur": "^4.1.5",
+ "open": "^11.0.0",
+ "ora": "^8.2.0",
+ "postcss": "^8.5.6",
+ "postcss-selector-parser": "^7.1.0",
+ "prompts": "^2.4.2",
+ "recast": "^0.23.11",
+ "stringify-object": "^5.0.0",
+ "tailwind-merge": "^3.0.1",
+ "ts-morph": "^26.0.0",
+ "tsconfig-paths": "^4.2.0",
+ "undici": "^7.27.2",
+ "validate-npm-package-name": "^7.0.1",
+ "zod": "^3.24.1",
+ "zod-to-json-schema": "^3.24.6"
+ },
+ "bin": {
+ "shadcn": "dist/index.js"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/shadcn/node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/shadcn/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/shadcn/node_modules/tsconfig-paths": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
+ "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
+ "license": "MIT",
+ "dependencies": {
+ "json5": "^2.2.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/shadcn/node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/sharp": {
"version": "0.35.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz",
@@ -6061,7 +8599,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -6074,7 +8611,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6084,7 +8620,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
"integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -6104,7 +8639,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -6121,7 +8655,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -6140,7 +8673,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -6156,6 +8688,43 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "license": "MIT"
+ },
+ "node_modules/sonner": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
+ "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -6172,6 +8741,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/stdin-discarder": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -6186,6 +8776,56 @@
"node": ">= 0.4"
}
},
+ "node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+ "license": "MIT"
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/string.prototype.includes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
@@ -6300,16 +8940,68 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/stringify-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz",
+ "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "get-own-enumerable-keys": "^1.0.0",
+ "is-obj": "^3.0.0",
+ "is-regexp": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/stringify-object?sponsor=1"
+ }
+ },
+ "node_modules/stringify-object/node_modules/is-obj": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz",
+ "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
+ "node_modules/strip-final-newline": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+ "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -6372,6 +9064,42 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/systeminformation": {
+ "version": "5.33.1",
+ "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.1.tgz",
+ "integrity": "sha512-DEN6ICHk3Tk0Uf/hrAHh7xlt7iL5CJFBtPZinA0H62DrGG/KPKqq/Nzj6lCXPS4Ay/sf/14zNnk9LpqKzBIc+w==",
+ "license": "MIT",
+ "os": [
+ "darwin",
+ "linux",
+ "win32",
+ "freebsd",
+ "openbsd",
+ "netbsd",
+ "sunos",
+ "android"
+ ],
+ "bin": {
+ "systeminformation": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "funding": {
+ "type": "Buy me a coffee",
+ "url": "https://www.buymeacoffee.com/systeminfo"
+ }
+ },
+ "node_modules/tailwind-merge": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz",
+ "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
@@ -6393,6 +9121,12 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
"node_modules/tinyglobby": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
@@ -6445,7 +9179,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -6454,6 +9187,15 @@
"node": ">=8.0"
}
},
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
@@ -6467,6 +9209,16 @@
"typescript": ">=4.8.4"
}
},
+ "node_modules/ts-morph": {
+ "version": "26.0.0",
+ "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz",
+ "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@ts-morph/common": "~0.27.0",
+ "code-block-writer": "^13.0.3"
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
@@ -6499,6 +9251,15 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/tw-animate-css": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
+ "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Wombosvideo"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -6512,6 +9273,37 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/type-is": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
+ "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^2.0.0",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/type-is/node_modules/content-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
+ "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
@@ -6594,7 +9386,7 @@
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
- "dev": true,
+ "devOptional": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -6647,6 +9439,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/undici": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
+ "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@@ -6654,6 +9455,36 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/unrs-resolver": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz",
@@ -6696,7 +9527,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -6733,11 +9563,43 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/validate-npm-package-name": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz",
+ "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==",
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -6848,11 +9710,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/wsl-utils": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz",
+ "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-wsl": "^3.1.0",
+ "powershell-utils": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true,
"license": "ISC"
},
"node_modules/yocto-queue": {
@@ -6868,16 +9751,51 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yocto-spinner": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.2.tgz",
+ "integrity": "sha512-DODGl1wJjA/s5pnJFKau9lIYHT81lnhob1i3e1TjxZRxEhWRKl74nTbWE6H5KlkViQQTo/Z29YFdxzTZAMY3ng==",
+ "license": "MIT",
+ "dependencies": {
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=18.19"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yoctocolors": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz",
+ "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/zod": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
+ "node_modules/zod-to-json-schema": {
+ "version": "3.25.2",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz",
+ "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==",
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.25.28 || ^4"
+ }
+ },
"node_modules/zod-validation-error": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
diff --git a/package.json b/package.json
index 5d4b83d..beab9c3 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,18 @@
"lint": "eslint"
},
"dependencies": {
+ "@base-ui/react": "^1.7.0",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^1.28.0",
"next": "16.3.0",
+ "next-themes": "^0.4.6",
"react": "19.2.8",
- "react-dom": "19.2.8"
+ "react-dom": "19.2.8",
+ "shadcn": "^4.16.1",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.6.0",
+ "tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
diff --git a/src/app/globals.css b/src/app/globals.css
index a2dc41e..f71e3bd 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,26 +1,130 @@
@import "tailwindcss";
+@import "tw-animate-css";
+@import "shadcn/tailwind.css";
-:root {
- --background: #ffffff;
- --foreground: #171717;
-}
+@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
+ --font-heading: var(--font-sans);
+ --color-sidebar-ring: var(--sidebar-ring);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar: var(--sidebar);
+ --color-chart-5: var(--chart-5);
+ --color-chart-4: var(--chart-4);
+ --color-chart-3: var(--chart-3);
+ --color-chart-2: var(--chart-2);
+ --color-chart-1: var(--chart-1);
+ --color-ring: var(--ring);
+ --color-input: var(--input);
+ --color-border: var(--border);
+ --color-destructive: var(--destructive);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-accent: var(--accent);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-muted: var(--muted);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-secondary: var(--secondary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-primary: var(--primary);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-popover: var(--popover);
+ --color-card-foreground: var(--card-foreground);
+ --color-card: var(--card);
+ --radius-sm: calc(var(--radius) * 0.6);
+ --radius-md: calc(var(--radius) * 0.8);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) * 1.4);
+ --radius-2xl: calc(var(--radius) * 1.8);
+ --radius-3xl: calc(var(--radius) * 2.2);
+ --radius-4xl: calc(var(--radius) * 2.6);
}
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
+:root {
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.87 0 0);
+ --chart-2: oklch(0.556 0 0);
+ --chart-3: oklch(0.439 0 0);
+ --chart-4: oklch(0.371 0 0);
+ --chart-5: oklch(0.269 0 0);
+ --radius: 0.625rem;
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+}
+
+.dark {
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.922 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.87 0 0);
+ --chart-2: oklch(0.556 0 0);
+ --chart-3: oklch(0.439 0 0);
+ --chart-4: oklch(0.371 0 0);
+ --chart-5: oklch(0.269 0 0);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
}
-}
-
-body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
-}
+ body {
+ @apply bg-background text-foreground;
+ }
+ html {
+ @apply font-sans;
+ }
+}
\ No newline at end of file
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 9852c15..5eece91 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,5 +1,9 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
+
+import { Toaster } from "@/components/ui/sonner";
+import { TooltipProvider } from "@/components/ui/tooltip";
+
import "./globals.css";
const geistSans = Geist({
@@ -13,17 +17,21 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Bestellübersicht – Speisekarte24",
+ description: "Bestellungen annehmen, übermitteln und bearbeiten.",
};
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
-
{children}
+
+ {children}
+ {/* App läuft bewusst nur im Light Mode – Systemtheme nicht übernehmen. */}
+
+
);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index c887311..24ad6b4 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,69 +1,28 @@
-import Image from "next/image";
+import { OrdersView } from "@/components/orders/orders-view";
+import { createOrders } from "@/lib/data";
+
+/** Die Demo-Daten liegen relativ zur aktuellen Uhrzeit, deshalb kein statisches Prerendering. */
+export const dynamic = "force-dynamic";
+
+/** Server-seitiger "Datenabruf": liefert Bestellungen samt der Zeit, auf die sie sich beziehen. */
+async function loadOrders() {
+ const now = Date.now();
+ return { now, orders: createOrders(now) };
+}
+
+export default async function Home() {
+ const { now, orders } = await loadOrders();
-export default function Home() {
return (
-
-
-
-
-
- To get started, edit the{" "}
-
- page.tsx
- {" "}
- file.
-
-
- Looking for a starting point or more instructions? Head over to{" "}
-
- Templates
- {" "}
- or the{" "}
-
- Learning
- {" "}
- center.
-
-
-
-
-
+
+
+
+
+
);
}
diff --git a/src/components/orders/actions.ts b/src/components/orders/actions.ts
new file mode 100644
index 0000000..817a068
--- /dev/null
+++ b/src/components/orders/actions.ts
@@ -0,0 +1,180 @@
+import {
+ Ban,
+ ExternalLink,
+ MessageCircle,
+ PhoneCall,
+ PhoneForwarded,
+ ShieldAlert,
+ Smartphone,
+ Voicemail,
+ XCircle,
+ type LucideIcon,
+} from "lucide-react";
+
+import { telHref, whatsAppHref } from "@/lib/format";
+import type { Order, OrderAction, OrderStatus } from "@/lib/types";
+
+export type { OrderAction };
+
+/** Status, den eine Aktion auf der Bestellung setzt. Aktionen ohne Eintrag ändern nichts. */
+export const ACTION_STATUS: Partial> = {
+ uebermittelt: "uebermittelt",
+ nicht_uebermittelt: "nicht_uebermittelt",
+ rueckruf: "rueckruf",
+ storno: "storniert",
+ fake: "fake",
+ stornieren: "storniert",
+ sos: "storniert",
+ telefonisch_uebermittelt: "telefonisch",
+};
+
+/** Aktionen, nach denen der Gastronom als bestätigt gilt. */
+export const CONFIRMING_ACTIONS: OrderAction[] = ["uebermittelt", "telefonisch_uebermittelt"];
+
+export const ACTION_TOAST: Partial> = {
+ uebermittelt: "Als übermittelt markiert",
+ gastronom_voice: "Voice-Message an Gastronom gesendet",
+ nicht_uebermittelt: "Als nicht übermittelt markiert – Kunde und Gastronom informiert",
+ rueckruf: "Rückrufhinweis an Kunden gesendet",
+ storno: "Bestellung storniert – Kunde per E-Mail informiert",
+ stornieren: "Bestellung storniert",
+ fake: "Als Fake markiert",
+ gastronom_anruf: "Direktanruf beim Gastronom vermerkt",
+ sos: "SOS ausgelöst – Bestellung storniert, Gastronom für heute geschlossen",
+ telefonisch_uebermittelt: "Als telefonisch übermittelt markiert",
+};
+
+export type ActionDef = {
+ key: string;
+ label: string;
+ /** Kurzform für die Schnellleiste auf der Karte. */
+ short: string;
+ icon: LucideIcon;
+ /** Gesetzt bei Links (Telefon, WhatsApp, ORDER WebApp). */
+ href?: string;
+ external?: boolean;
+ /** Reiner Telefonanschluss – steckt bereits im Anruf-Dialog. */
+ phone?: boolean;
+ /** Gesetzt bei Aktionen, die den Bestellstatus ändern oder eine Nachricht auslösen. */
+ action?: OrderAction;
+ destructive?: boolean;
+};
+
+/** Kontaktwege zum Gastronomen – Buttons 1–6 der alten Oberfläche. */
+export function gastronomActions({ restaurant }: Order): ActionDef[] {
+ const defs: ActionDef[] = [
+ {
+ key: "phone1",
+ label: `Telefon 1 · ${restaurant.phone1}`,
+ short: "Telefon 1",
+ phone: true,
+ icon: PhoneCall,
+ href: telHref(restaurant.phone1),
+ action: "gastronom_anruf",
+ },
+ ];
+
+ if (restaurant.phone2) {
+ defs.push({
+ key: "phone2",
+ label: `Telefon 2 · ${restaurant.phone2}`,
+ short: "Telefon 2",
+ phone: true,
+ icon: PhoneCall,
+ href: telHref(restaurant.phone2),
+ });
+ }
+ if (restaurant.mobile) {
+ defs.push({
+ key: "mobile",
+ label: `Mobil · ${restaurant.mobile}`,
+ short: "Mobil",
+ phone: true,
+ icon: Smartphone,
+ href: telHref(restaurant.mobile),
+ });
+ }
+
+ defs.push({
+ key: "voice",
+ label: "Voice-Message senden",
+ short: "Voice",
+ icon: Voicemail,
+ action: "gastronom_voice",
+ });
+
+ if (restaurant.mobile) {
+ defs.push({
+ key: "whatsapp",
+ label: "WhatsApp-Message senden",
+ short: "WhatsApp",
+ icon: MessageCircle,
+ href: whatsAppHref(restaurant.mobile),
+ external: true,
+ });
+ }
+
+ defs.push({
+ key: "order",
+ label: "ORDER WebApp öffnen",
+ short: "ORDER",
+ icon: ExternalLink,
+ href: restaurant.orderUrl,
+ external: true,
+ });
+
+ return defs;
+}
+
+/** Bearbeitungsschritte zur Bestellung – Buttons 7–13 der alten Oberfläche. */
+export function bearbeitungActions({ customer }: Order): ActionDef[] {
+ return [
+ {
+ key: "call_customer",
+ label: `Kunde anrufen · ${customer.phone}`,
+ short: "Kunde anrufen",
+ phone: true,
+ icon: PhoneCall,
+ href: telHref(customer.phone),
+ action: "kunde_anrufen",
+ },
+ {
+ key: "phone_transfer",
+ label: "Telefonisch übermittelt",
+ short: "Telefonisch",
+ icon: PhoneForwarded,
+ action: "telefonisch_uebermittelt",
+ },
+ {
+ key: "not_transferred",
+ label: "Nicht übermittelt",
+ short: "Nicht übermittelt",
+ icon: Ban,
+ action: "nicht_uebermittelt",
+ },
+ {
+ key: "callback",
+ label: "Rückrufhinweis senden",
+ short: "Rückruf",
+ icon: PhoneForwarded,
+ action: "rueckruf",
+ },
+ { key: "fake", label: "Als Fake markieren", short: "Fake", icon: ShieldAlert, action: "fake" },
+ {
+ key: "storno",
+ label: "Storno (Kunde per E-Mail)",
+ short: "Storno",
+ icon: XCircle,
+ action: "storno",
+ destructive: true,
+ },
+ {
+ key: "cancel",
+ label: "Stornieren (ohne E-Mail)",
+ short: "Stornieren",
+ icon: Ban,
+ action: "stornieren",
+ destructive: true,
+ },
+ ];
+}
diff --git a/src/components/orders/order-actions.tsx b/src/components/orders/order-actions.tsx
new file mode 100644
index 0000000..a93c25b
--- /dev/null
+++ b/src/components/orders/order-actions.tsx
@@ -0,0 +1,272 @@
+"use client";
+
+import * as React from "react";
+import {
+ Check,
+ ExternalLink,
+ MoreHorizontal,
+ PhoneCall,
+ Smartphone,
+ type LucideIcon,
+} from "lucide-react";
+
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from "@/components/ui/alert-dialog";
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { ButtonGroup } from "@/components/ui/button-group";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { telHref } from "@/lib/format";
+import type { Order } from "@/lib/types";
+
+import {
+ bearbeitungActions,
+ gastronomActions,
+ type ActionDef,
+ type OrderAction,
+} from "./actions";
+
+type Props = {
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+};
+
+/** Schnellzugriffe in der Tabellenzeile; alles Weitere steckt im Menü und im Detail-Dialog. */
+export function OrderActions({ order, onAction }: Props) {
+ const [confirmOpen, setConfirmOpen] = React.useState(false);
+ const [callOpen, setCallOpen] = React.useState(false);
+
+ return (
+ <>
+
+ setCallOpen(true)}
+ >
+
+
+
+ setConfirmOpen(true)}
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+
+ Gastronom kontaktieren
+ {gastronomActions(order).map((def) => (
+
+ ))}
+
+
+
+
+
+ Bestellung bearbeiten
+ {bearbeitungActions(order).map((def) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ Anrufen
+
+ Bestellung #{order.number} · {order.restaurant.name}
+
+
+
+
+ onAction(order, "gastronom_anruf")}
+ />
+ {order.restaurant.phone2 && (
+
+ )}
+ {order.restaurant.mobile && (
+
+ )}
+
+
+
+ onAction(order, "kunde_anrufen")}
+ />
+
+
+
+
+
+
+
+ Bestellung als übermittelt markieren?
+
+ Bestellung #{order.number} bei {order.restaurant.name} gilt danach als bestätigt.
+ Die Eskalation stoppt.
+
+
+
+ Abbrechen
+ {
+ onAction(order, "uebermittelt");
+ setConfirmOpen(false);
+ }}
+ >
+ Übermittelt
+
+
+
+
+ >
+ );
+}
+
+function CallGroup({ title, children }: { title: string; children: React.ReactNode }) {
+ return (
+
+ );
+}
+
+/** Ein wählbarer Anschluss im Anruf-Dialog. */
+function CallLink({
+ label,
+ phone,
+ icon: Icon = PhoneCall,
+ onClick,
+}: {
+ label: string;
+ phone: string;
+ icon?: LucideIcon;
+ onClick?: () => void;
+}) {
+ return (
+ }
+ >
+
+ {label}
+ {phone}
+
+ );
+}
+
+function MenuAction({
+ def,
+ order,
+ onAction,
+}: {
+ def: ActionDef;
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+}) {
+ const Icon = def.icon;
+ const handleClick = def.action ? () => onAction(order, def.action!) : undefined;
+
+ if (def.href) {
+ return (
+
+ }
+ >
+
+ {def.label}
+
+ );
+ }
+
+ return (
+
+
+ {def.label}
+
+ );
+}
diff --git a/src/components/orders/order-card.tsx b/src/components/orders/order-card.tsx
new file mode 100644
index 0000000..33b9cdb
--- /dev/null
+++ b/src/components/orders/order-card.tsx
@@ -0,0 +1,143 @@
+"use client";
+
+import * as React from "react";
+import { ChevronDown } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import { Card } from "@/components/ui/card";
+import { formatCurrency, formatTime } from "@/lib/format";
+import { PAYMENT_LABEL, TYPE_LABEL, type Order } from "@/lib/types";
+import { cn } from "@/lib/utils";
+
+import type { OrderAction } from "./actions";
+import { OrderActions } from "./order-actions";
+import { OrderQuickActions } from "./order-quick-actions";
+import { OrderTimeline } from "./order-timeline";
+import { StatusBadge } from "./status-badge";
+
+type Props = {
+ order: Order;
+ now: number;
+ onAction: (order: Order, action: OrderAction) => void;
+ onSelect: (order: Order) => void;
+ /** `list` legt die Felder nebeneinander statt untereinander. */
+ layout: "grid" | "list";
+};
+
+export function OrderCard({ order, now, onAction, onSelect, layout }: Props) {
+ const [timelineOpen, setTimelineOpen] = React.useState(false);
+
+ return (
+ onSelect(order)}
+ >
+
+
+
+ #{order.number}
+
+
+
+ {/* Aktionen dürfen den Detail-Dialog der Karte nicht mit öffnen. */}
+
event.stopPropagation()}
+ >
+
+
+
+
+
+
+ {order.restaurant.name}
+
+ {order.restaurant.city} · {order.restaurant.hours}
+
+
+
+ {order.customer.name}
+
+ {order.customer.email}
+
+
+
event.stopPropagation()}
+ >
+ setTimelineOpen((open) => !open)}
+ >
+
+ {timelineOpen ? "Verlauf ausblenden" : "Verlauf anzeigen"}
+
+
+ {/* Verlauf bleibt eingeklappt, sonst wird die Liste unlesbar lang. */}
+ {timelineOpen && (
+
+
+
+ )}
+
+ ) : undefined
+ }
+ >
+
+
+ {formatTime(order.receivedAt)}
+
+ {formatTime(order.dueAt)}
+
+
+ {TYPE_LABEL[order.type]}
+
+
+
+ {formatCurrency(order.total)}
+
+ {PAYMENT_LABEL[order.payment]}
+
+
+
+
+ {/* In der Liste ist Platz, alle Aktionen offen zu zeigen statt sie im Menü zu verstecken. */}
+ {layout === "list" && }
+
+ );
+}
+
+function Field({
+ label,
+ children,
+ extra,
+}: {
+ label: string;
+ children: React.ReactNode;
+ /** Steht unter dem Feldinhalt, außerhalb des Abschneidens. */
+ extra?: React.ReactNode;
+}) {
+ return (
+
+
{label}
+
{children}
+ {extra}
+
+ );
+}
diff --git a/src/components/orders/order-detail-dialog.tsx b/src/components/orders/order-detail-dialog.tsx
new file mode 100644
index 0000000..b0e8926
--- /dev/null
+++ b/src/components/orders/order-detail-dialog.tsx
@@ -0,0 +1,174 @@
+"use client";
+
+import { ExternalLink, FileText } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Separator } from "@/components/ui/separator";
+import { formatCurrency, formatDate, formatTime } from "@/lib/format";
+import { PAYMENT_LABEL, TYPE_LABEL, type Order } from "@/lib/types";
+
+import {
+ bearbeitungActions,
+ gastronomActions,
+ type ActionDef,
+ type OrderAction,
+} from "./actions";
+import { OrderTimeline } from "./order-timeline";
+import { StatusBadge } from "./status-badge";
+
+type Props = {
+ order: Order | null;
+ now: number;
+ onOpenChange: (open: boolean) => void;
+ onAction: (order: Order, action: OrderAction) => void;
+};
+
+export function OrderDetailDialog({ order, now, onOpenChange, onAction }: Props) {
+ return (
+
+
+ {order && (
+ <>
+
+
+ Bestellung #{order.number}
+
+
+
+ {TYPE_LABEL[order.type]} · Eingang {formatDate(order.receivedAt)} um{" "}
+ {formatTime(order.receivedAt)} Uhr
+
+
+
+
+
+ {order.restaurant.name}
+
+ {order.restaurant.city} · geöffnet {order.restaurant.hours}
+
+
+
+ {order.customer.name}
+
+ {order.customer.email} · {order.customer.phone}
+
+
+
+ Eingang {formatTime(order.receivedAt)} Uhr
+
+ Gewünscht {formatTime(order.dueAt)} Uhr
+
+
+
+ {formatCurrency(order.total)}
+
+ {order.itemCount} Artikel · {PAYMENT_LABEL[order.payment]}
+
+
+
+
+
+ }
+ >
+
+ Bestellung als PDF öffnen
+
+ }
+ >
+
+ Im Backoffice öffnen
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ );
+}
+
+function Field({ label, children }: { label: string; children: React.ReactNode }) {
+ return (
+
+ );
+}
+
+function ActionGroup({
+ title,
+ defs,
+ order,
+ onAction,
+}: {
+ title: string;
+ defs: ActionDef[];
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+}) {
+ return (
+
+
{title}
+
+ {defs.map((def) => {
+ const Icon = def.icon;
+ const handleClick = def.action ? () => onAction(order, def.action!) : undefined;
+
+ return (
+
+ ) : undefined
+ }
+ >
+
+ {def.label}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/src/components/orders/order-quick-actions.tsx b/src/components/orders/order-quick-actions.tsx
new file mode 100644
index 0000000..a2df104
--- /dev/null
+++ b/src/components/orders/order-quick-actions.tsx
@@ -0,0 +1,86 @@
+"use client";
+
+import { Button } from "@/components/ui/button";
+import type { Order } from "@/lib/types";
+
+import { bearbeitungActions, gastronomActions, type ActionDef, type OrderAction } from "./actions";
+
+type Props = {
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+};
+
+/**
+ * Alle Aktionen offen auf der Karte, wie in der alten Oberfläche: oben die Wege zum
+ * Gastronomen, unten die Bearbeitungsschritte zur Bestellung.
+ */
+export function OrderQuickActions({ order, onAction }: Props) {
+ return (
+ // Aktionen dürfen den Detail-Dialog der Karte nicht mit öffnen.
+ event.stopPropagation()}
+ >
+ {/* Reine Telefonnummern bleiben draußen – die stecken im Anruf-Button der Kopfzeile. */}
+ !def.phone)}
+ order={order}
+ onAction={onAction}
+ />
+ !def.phone)}
+ order={order}
+ onAction={onAction}
+ />
+
+ );
+}
+
+function Row({
+ title,
+ defs,
+ order,
+ onAction,
+}: {
+ title: string;
+ defs: ActionDef[];
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+}) {
+ return (
+
+
{title}
+
+ {defs.map((def) => {
+ const Icon = def.icon;
+ const handleClick = def.action ? () => onAction(order, def.action!) : undefined;
+
+ return (
+
+ ) : undefined
+ }
+ >
+
+ {def.short}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/src/components/orders/order-timeline.tsx b/src/components/orders/order-timeline.tsx
new file mode 100644
index 0000000..95ca53c
--- /dev/null
+++ b/src/components/orders/order-timeline.tsx
@@ -0,0 +1,115 @@
+"use client";
+
+import { Check, CircleAlert, Clock, Minus, TriangleAlert } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import { formatTime } from "@/lib/format";
+import { buildTimeline, type StepState, type TimelineStep } from "@/lib/timeline";
+import type { Order, OrderAction } from "@/lib/types";
+import { cn } from "@/lib/utils";
+
+type Props = {
+ order: Order;
+ now: number;
+ onAction: (order: Order, action: OrderAction) => void;
+};
+
+const ICON: Record = {
+ done: Check,
+ due: CircleAlert,
+ pending: Clock,
+ skipped: Minus,
+};
+
+export function OrderTimeline({ order, now, onAction }: Props) {
+ const steps = buildTimeline(order, now);
+
+ return (
+
+
Verlauf
+
+ {steps.map((step, index) => (
+
+ ))}
+
+
+ );
+}
+
+function Step({
+ step,
+ last,
+ order,
+ onAction,
+}: {
+ step: TimelineStep;
+ last: boolean;
+ order: Order;
+ onAction: (order: Order, action: OrderAction) => void;
+}) {
+ const Icon = ICON[step.state];
+ const danger = step.danger && step.state !== "pending" && step.state !== "skipped";
+
+ return (
+
+
+
+
+
+ {!last && }
+
+
+
+
+
+ {step.label}
+
+ {step.at !== undefined && (
+
+ {step.state === "pending" ? "ab " : ""}
+ {formatTime(new Date(step.at).toISOString())} Uhr
+
+ )}
+
+
+ {step.description && (
+
{step.description}
+ )}
+
+ {step.state === "due" && step.action && (
+
onAction(order, step.action!)}
+ >
+ {step.danger && }
+ {step.danger ? "SOS auslösen" : "Jetzt erledigen"}
+
+ )}
+
+
+ );
+}
diff --git a/src/components/orders/orders-table.tsx b/src/components/orders/orders-table.tsx
new file mode 100644
index 0000000..e60cb14
--- /dev/null
+++ b/src/components/orders/orders-table.tsx
@@ -0,0 +1,215 @@
+"use client";
+
+import { ArrowDown, ArrowUp, ChevronsUpDown, TriangleAlert } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import { formatCurrency, formatTime } from "@/lib/format";
+import { currentStep } from "@/lib/timeline";
+import { PAYMENT_LABEL, type Order } from "@/lib/types";
+import { cn } from "@/lib/utils";
+
+import type { OrderAction } from "./actions";
+import { OrderActions } from "./order-actions";
+import { StatusBadge } from "./status-badge";
+
+export type SortKey =
+ | "number"
+ | "status"
+ | "receivedAt"
+ | "dueAt"
+ | "restaurant"
+ | "customer"
+ | "total";
+
+export type SortState = { key: SortKey; dir: "asc" | "desc" };
+
+type Props = {
+ orders: Order[];
+ /** Uhrzeit für den Verlauf – kommt aus der laufenden Uhr der Ansicht. */
+ now: number;
+ sort: SortState;
+ onSortChange: (key: SortKey) => void;
+ onAction: (order: Order, action: OrderAction) => void;
+ onSelect: (order: Order) => void;
+};
+
+export function OrdersTable({ orders, now, sort, onSortChange, onAction, onSelect }: Props) {
+ return (
+
+
+
+
+
+ Nr.
+
+
+ Status
+
+
+ Gastronom
+
+
+ Kunde
+
+
+ Eingang
+
+
+ Gewünscht
+
+ Verlauf
+
+ Betrag
+
+ Zahlart
+ Aktionen
+
+
+
+ {orders.length === 0 && (
+
+
+ Keine Bestellungen gefunden.
+
+
+ )}
+
+ {orders.map((order) => (
+ onSelect(order)}
+ >
+
+ {order.number}
+
+
+
+
+
+ {order.restaurant.name}
+
+ {order.restaurant.city} · {order.restaurant.hours}
+
+
+
+ {order.customer.name}
+ {order.customer.email}
+
+
+
+ {formatTime(order.receivedAt)}
+
+
+
+ {formatTime(order.dueAt)}
+
+ {/* Der Schritt-Button darf den Detail-Dialog der Zeile nicht mit öffnen. */}
+ event.stopPropagation()}>
+
+
+
+ {formatCurrency(order.total)}
+
+
+ {PAYMENT_LABEL[order.payment]}
+
+ {/* Aktionen dürfen den Detail-Dialog der Zeile nicht mit öffnen. */}
+ event.stopPropagation()}>
+
+
+
+
+
+ ))}
+
+
+
+ );
+}
+
+/** Aktueller Punkt der Eskalation samt Button für den fälligen Schritt. */
+function StepCell({
+ order,
+ now,
+ onAction,
+}: {
+ order: Order;
+ now: number;
+ onAction: (order: Order, action: OrderAction) => void;
+}) {
+ const step = currentStep(order, now);
+ const due = step.state === "due";
+
+ return (
+
+
+ {step.short}
+
+ {due && step.action && (
+ onAction(order, step.action!)}
+ >
+ {step.danger && }
+ {step.danger ? "SOS" : "Erledigen"}
+
+ )}
+
+ );
+}
+
+function SortableHead({
+ sortKey,
+ sort,
+ onSortChange,
+ align = "left",
+ className,
+ children,
+}: {
+ sortKey: SortKey;
+ sort: SortState;
+ onSortChange: (key: SortKey) => void;
+ align?: "left" | "right";
+ className?: string;
+ children: React.ReactNode;
+}) {
+ const active = sort.key === sortKey;
+ const Icon = !active ? ChevronsUpDown : sort.dir === "asc" ? ArrowUp : ArrowDown;
+
+ return (
+
+
+ onSortChange(sortKey)}
+ >
+ {children}
+
+
+
+
+ );
+}
diff --git a/src/components/orders/orders-view.tsx b/src/components/orders/orders-view.tsx
new file mode 100644
index 0000000..8f0cd96
--- /dev/null
+++ b/src/components/orders/orders-view.tsx
@@ -0,0 +1,606 @@
+"use client";
+
+import * as React from "react";
+import {
+ ArrowDownWideNarrow,
+ ArrowUpNarrowWide,
+ ChevronLeft,
+ ChevronRight,
+ ChevronsLeft,
+ ChevronsRight,
+ LayoutGrid,
+ SlidersHorizontal,
+ Rows3,
+ Search,
+ Table2,
+ X,
+} from "lucide-react";
+import { toast } from "sonner";
+
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import {
+ Sheet,
+ SheetContent,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from "@/components/ui/sheet";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { useIsMobile } from "@/hooks/use-media-query";
+import { formatCurrency } from "@/lib/format";
+import {
+ PAYMENT_LABEL,
+ STATUS_LABEL,
+ TYPE_LABEL,
+ type Order,
+ type OrderStatus,
+ type OrderType,
+ type PaymentMethod,
+ effectiveStatus,
+} from "@/lib/types";
+
+import { ACTION_STATUS, ACTION_TOAST, CONFIRMING_ACTIONS, type OrderAction } from "./actions";
+import { OrderCard } from "./order-card";
+import { OrderDetailDialog } from "./order-detail-dialog";
+import { OrdersTable, type SortKey, type SortState } from "./orders-table";
+
+const ALL = "alle";
+const PAGE_SIZES = [10, 25, 50, 100];
+
+type ViewMode = "table" | "list" | "grid";
+
+const VIEW_MODES: { value: ViewMode; label: string; icon: typeof Table2 }[] = [
+ { value: "table", label: "Tabelle", icon: Table2 },
+ { value: "list", label: "Liste", icon: Rows3 },
+ { value: "grid", label: "Raster", icon: LayoutGrid },
+];
+
+/** Sortierfelder für Listen- und Rasteransicht, in denen es keine Spaltenköpfe gibt. */
+const SORT_LABEL: Record = {
+ number: "Nummer",
+ status: "Status",
+ restaurant: "Gastronom",
+ customer: "Kunde",
+ receivedAt: "Eingang",
+ dueAt: "Gewünschte Zeit",
+ total: "Betrag",
+};
+
+
+type Props = {
+ initialOrders: Order[];
+ /** Serverzeit des Renderings – Startwert der Uhr für die 15-Minuten-Regel. */
+ renderedAt: number;
+};
+
+export function OrdersView({ initialOrders, renderedAt }: Props) {
+ const [orders, setOrders] = React.useState(initialOrders);
+ const [tab, setTab] = React.useState("allgemein");
+ const [search, setSearch] = React.useState("");
+ const [status, setStatus] = React.useState(ALL);
+ const [type, setType] = React.useState(ALL);
+ const [restaurant, setRestaurant] = React.useState(ALL);
+ const [payment, setPayment] = React.useState(ALL);
+ const [sort, setSort] = React.useState({ key: "number", dir: "desc" });
+ const [pageSize, setPageSize] = React.useState(25);
+ const [page, setPage] = React.useState(1);
+ const [selectedId, setSelectedId] = React.useState(null);
+ const [view, setView] = React.useState(null);
+ const [now, setNow] = React.useState(renderedAt);
+ const [filtersOpen, setFiltersOpen] = React.useState(false);
+
+ // Die Uhr tickt weiter, damit Bestellungen ohne Zutun in "Nicht übermittelt" kippen.
+ React.useEffect(() => {
+ const id = setInterval(() => setNow(Date.now()), 30_000);
+ return () => clearInterval(id);
+ }, []);
+
+ // Ohne eigene Wahl entscheidet die Bildschirmbreite: mobil Liste, sonst Tabelle.
+ const isMobile = useIsMobile();
+ // Raster fällt mobil weg – einspaltig sähe es identisch zur Liste aus.
+ const viewModes = isMobile ? VIEW_MODES.filter((m) => m.value !== "grid") : VIEW_MODES;
+ const chosenView = view ?? (isMobile ? "list" : "table");
+ const viewMode: ViewMode = isMobile && chosenView === "grid" ? "list" : chosenView;
+ const activeView = viewModes.find((m) => m.value === viewMode) ?? viewModes[0];
+
+ const restaurants = React.useMemo(
+ () => [...new Set(initialOrders.map((o) => o.restaurant.name))].sort(),
+ [initialOrders],
+ );
+
+ /** Der abgelaufene Status ersetzt den gespeicherten, bevor irgendwo gefiltert wird. */
+ const dated = React.useMemo(
+ () => orders.map((o) => ({ ...o, status: effectiveStatus(o, now) })),
+ [orders, now],
+ );
+
+ const undeliveredCount = dated.filter((o) => o.status === "nicht_uebermittelt").length;
+
+ // Der Dialog liest über die Id nach, damit er Aktionen sofort widerspiegelt.
+ const selected = dated.find((o) => o.id === selectedId) ?? null;
+
+ const filtered = React.useMemo(() => {
+ const q = search.trim().toLowerCase();
+
+ const rows = dated.filter((o) => {
+ if (tab === "nicht_uebermittelt" && o.status !== "nicht_uebermittelt") return false;
+ if (status !== ALL && o.status !== status) return false;
+ if (type !== ALL && o.type !== type) return false;
+ if (restaurant !== ALL && o.restaurant.name !== restaurant) return false;
+ if (payment !== ALL && o.payment !== payment) return false;
+ if (!q) return true;
+
+ return [
+ String(o.number),
+ o.restaurant.name,
+ o.restaurant.city,
+ o.customer.name,
+ o.customer.email,
+ o.customer.phone,
+ STATUS_LABEL[o.status],
+ TYPE_LABEL[o.type],
+ ]
+ .join(" ")
+ .toLowerCase()
+ .includes(q);
+ });
+
+ const factor = sort.dir === "asc" ? 1 : -1;
+ return rows.sort((a, b) => factor * compare(a, b, sort.key));
+ }, [dated, tab, search, status, type, restaurant, payment, sort]);
+
+ const sum = filtered.reduce((acc, o) => acc + o.total, 0);
+ const filtersActive =
+ search !== "" || status !== ALL || type !== ALL || restaurant !== ALL || payment !== ALL;
+
+ const pageCount = Math.max(1, Math.ceil(filtered.length / pageSize));
+ const currentPage = Math.min(page, pageCount);
+ const pageStart = (currentPage - 1) * pageSize;
+ const pageRows = filtered.slice(pageStart, pageStart + pageSize);
+
+ /** Jede Änderung an Filtern, Suche oder Sortierung springt zurück auf Seite 1. */
+ function update(setter: (value: T) => void) {
+ return (value: T) => {
+ setter(value);
+ setPage(1);
+ };
+ }
+
+ function handleSort(key: SortKey) {
+ setSort((prev) =>
+ prev.key === key
+ ? { key, dir: prev.dir === "asc" ? "desc" : "asc" }
+ : { key, dir: key === "number" ? "desc" : "asc" },
+ );
+ setPage(1);
+ }
+
+ /** Wechselt das Sortierfeld, ohne die Richtung umzuschalten. */
+ function setSortKey(key: SortKey) {
+ setSort((prev) =>
+ prev.key === key ? prev : { key, dir: key === "number" ? "desc" : "asc" },
+ );
+ setPage(1);
+ }
+
+ function resetFilters() {
+ setSearch("");
+ setStatus(ALL);
+ setType(ALL);
+ setRestaurant(ALL);
+ setPayment(ALL);
+ setPage(1);
+ }
+
+ const activeFilters = [status, type, restaurant, payment].filter((v) => v !== ALL).length;
+
+ const filterSelects = (
+ <>
+
+
+ [r, r] as [string, string])}
+ />
+
+ >
+ );
+
+ function handleAction(order: Order, action: OrderAction) {
+ const at = new Date().toISOString();
+ const next = ACTION_STATUS[action];
+
+ setOrders((prev) =>
+ prev.map((o) =>
+ o.id === order.id
+ ? {
+ ...o,
+ status: next ?? o.status,
+ confirmedAt: CONFIRMING_ACTIONS.includes(action) ? at : o.confirmedAt,
+ events: [...o.events, { type: action, at }],
+ }
+ : o,
+ ),
+ );
+
+ const message = ACTION_TOAST[action];
+ if (message) toast.success(message, { description: `Bestellung #${order.number}` });
+ }
+
+ return (
+
+
+
+ Allgemein
+
+ {orders.length}
+
+
+ {/* Offene Fälle sollen ins Auge springen, deshalb rot statt neutral. */}
+ 0
+ ? "text-destructive hover:text-destructive data-active:text-destructive"
+ : undefined
+ }
+ >
+ {undeliveredCount > 0 && (
+
+
+
+
+ )}
+ Nicht übermittelt
+ 0 ? "destructive" : "secondary"}
+ className="ml-1.5 tabular-nums"
+ >
+ {undeliveredCount}
+
+
+
+
+
+
+ {/* Mobil zieht das Feld die Zeile, ab sm reicht eine feste Breite. */}
+
+
+ update(setSearch)(e.target.value)}
+ placeholder="Suche nach Nr., Gastronom, Kunde …"
+ className="pl-9"
+ />
+
+
+ {/* Filter und Ansicht sammeln sich rechts, die Suche bleibt links. */}
+
+ {/* Mobil würden fünf Selects die halbe Seite füllen – deshalb ins Sheet. */}
+ {isMobile ? (
+
+
+ }
+ >
+
+ {activeFilters > 0 && (
+
+ {activeFilters}
+
+ )}
+
+
+
+ Filter
+
+ {filterSelects}
+
+
+
+ Zurücksetzen
+
+ setFiltersOpen(false)}>
+ {filtered.length} Bestellungen anzeigen
+
+
+
+
+ ) : (
+ <>
+ {filterSelects}
+ {filtersActive && (
+
+
+ Zurücksetzen
+
+ )}
+ >
+ )}
+
+ {/* Ansicht als Icon-Menü, damit die Zeile nicht von drei Schaltern belegt wird. */}
+
+
+ }
+ >
+
+
+
+
+ Ansicht
+ setView((next as ViewMode) ?? viewMode)}
+ >
+ {viewModes.map(({ value, label, icon: Icon }) => (
+ // Radio-Einträge bleiben sonst offen stehen; hier ist die Wahl erledigt.
+
+
+ {label}
+
+ ))}
+
+
+
+
+
+
+
+ {/* Ohne Spaltenköpfe braucht es in Liste und Raster eigene Sortiersteuerung. */}
+ {viewMode !== "table" && (
+
+
+
setSortKey((next ?? "number") as SortKey)}
+ >
+
+
+ {(current: string | null) =>
+ // Mobil fehlt der Platz für das Präfix.
+ `${isMobile ? "" : "Sortieren: "}${SORT_LABEL[(current ?? "number") as SortKey]}`
+ }
+
+
+
+ {(Object.entries(SORT_LABEL) as [SortKey, string][]).map(([key, label]) => (
+
+ {label}
+
+ ))}
+
+
+
handleSort(sort.key)}
+ >
+ {sort.dir === "asc" ? : }
+
+
+
+ )}
+
+
+
+ {viewMode === "table" ? (
+ setSelectedId(order.id)}
+ />
+ ) : pageRows.length === 0 ? (
+
+ Keine Bestellungen gefunden.
+
+ ) : (
+
+ {pageRows.map((order) => (
+ setSelectedId(o.id)}
+ />
+ ))}
+
+ )}
+
+
+
+ {filtered.length} von {orders.length} Bestellungen · Summe {formatCurrency(sum)}
+
+
+
+
+ Zeilen pro Seite
+ update(setPageSize)(Number(next ?? 25))}
+ >
+
+ {(current: string | null) => current ?? "25"}
+
+
+ {PAGE_SIZES.map((size) => (
+
+ {size}
+
+ ))}
+
+
+
+
+
+ Seite {currentPage} von {pageCount}
+
+
+
+ setPage(1)}
+ >
+
+
+ setPage(currentPage - 1)}
+ >
+
+
+ setPage(currentPage + 1)}
+ >
+
+
+ setPage(pageCount)}
+ >
+
+
+
+
+
+
+ !open && setSelectedId(null)}
+ onAction={handleAction}
+ />
+
+ );
+}
+
+function FilterSelect({
+ value,
+ onValueChange,
+ placeholder,
+ options,
+}: {
+ value: string;
+ onValueChange: (value: string) => void;
+ placeholder: string;
+ options: [string, string][];
+}) {
+ const labels = Object.fromEntries(options);
+
+ return (
+ onValueChange(next ?? ALL)}>
+
+
+ {(current: string | null) =>
+ current && current !== ALL ? labels[current] : `${placeholder}: Alle`
+ }
+
+
+
+ {placeholder}: Alle
+ {options.map(([key, label]) => (
+
+ {label}
+
+ ))}
+
+
+ );
+}
+
+function compare(a: Order, b: Order, key: SortKey) {
+ switch (key) {
+ case "number":
+ case "total":
+ return a[key] - b[key];
+ case "receivedAt":
+ case "dueAt":
+ return a[key].localeCompare(b[key]);
+ case "status":
+ return STATUS_LABEL[a.status].localeCompare(STATUS_LABEL[b.status], "de");
+ case "restaurant":
+ return a.restaurant.name.localeCompare(b.restaurant.name, "de");
+ case "customer":
+ return a.customer.name.localeCompare(b.customer.name, "de");
+ }
+}
diff --git a/src/components/orders/status-badge.tsx b/src/components/orders/status-badge.tsx
new file mode 100644
index 0000000..069e06d
--- /dev/null
+++ b/src/components/orders/status-badge.tsx
@@ -0,0 +1,31 @@
+import { Badge } from "@/components/ui/badge";
+import { STATUS_LABEL, type OrderStatus } from "@/lib/types";
+
+const VARIANT: Record = {
+ neu: "default",
+ uebermittelt: "secondary",
+ telefonisch: "secondary",
+ nicht_uebermittelt: "destructive",
+ rueckruf: "outline",
+ storniert: "destructive",
+ fake: "outline",
+};
+
+const DOT: Record = {
+ neu: "bg-blue-500",
+ uebermittelt: "bg-emerald-500",
+ telefonisch: "bg-emerald-500",
+ nicht_uebermittelt: "bg-destructive",
+ rueckruf: "bg-amber-500",
+ storniert: "bg-destructive",
+ fake: "bg-zinc-400",
+};
+
+export function StatusBadge({ status }: { status: OrderStatus }) {
+ return (
+
+
+ {STATUS_LABEL[status]}
+
+ );
+}
diff --git a/src/components/ui/alert-dialog.tsx b/src/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..0ee2c5f
--- /dev/null
+++ b/src/components/ui/alert-dialog.tsx
@@ -0,0 +1,187 @@
+"use client"
+
+import * as React from "react"
+import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+
+function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
+ return
+}
+
+function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
+ return (
+
+ )
+}
+
+function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
+ return (
+
+ )
+}
+
+function AlertDialogOverlay({
+ className,
+ ...props
+}: AlertDialogPrimitive.Backdrop.Props) {
+ return (
+
+ )
+}
+
+function AlertDialogContent({
+ className,
+ size = "default",
+ ...props
+}: AlertDialogPrimitive.Popup.Props & {
+ size?: "default" | "sm"
+}) {
+ return (
+
+
+
+
+ )
+}
+
+function AlertDialogHeader({
+ className,
+ ...props
+}: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function AlertDialogFooter({
+ className,
+ ...props
+}: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function AlertDialogMedia({
+ className,
+ ...props
+}: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function AlertDialogTitle({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogDescription({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogAction({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogCancel({
+ className,
+ variant = "outline",
+ size = "default",
+ ...props
+}: AlertDialogPrimitive.Close.Props &
+ Pick, "variant" | "size">) {
+ return (
+ }
+ {...props}
+ />
+ )
+}
+
+export {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogMedia,
+ AlertDialogOverlay,
+ AlertDialogPortal,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+}
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
new file mode 100644
index 0000000..b20959d
--- /dev/null
+++ b/src/components/ui/badge.tsx
@@ -0,0 +1,52 @@
+import { mergeProps } from "@base-ui/react/merge-props"
+import { useRender } from "@base-ui/react/use-render"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
+ secondary:
+ "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
+ destructive:
+ "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
+ outline:
+ "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
+ ghost:
+ "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function Badge({
+ className,
+ variant = "default",
+ render,
+ ...props
+}: useRender.ComponentProps<"span"> & VariantProps) {
+ return useRender({
+ defaultTagName: "span",
+ props: mergeProps<"span">(
+ {
+ className: cn(badgeVariants({ variant }), className),
+ },
+ props
+ ),
+ render,
+ state: {
+ slot: "badge",
+ variant,
+ },
+ })
+}
+
+export { Badge, badgeVariants }
diff --git a/src/components/ui/button-group.tsx b/src/components/ui/button-group.tsx
new file mode 100644
index 0000000..3c97c26
--- /dev/null
+++ b/src/components/ui/button-group.tsx
@@ -0,0 +1,87 @@
+import { mergeProps } from "@base-ui/react/merge-props"
+import { useRender } from "@base-ui/react/use-render"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+import { Separator } from "@/components/ui/separator"
+
+const buttonGroupVariants = cva(
+ "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
+ {
+ variants: {
+ orientation: {
+ horizontal:
+ "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
+ vertical:
+ "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0",
+ },
+ },
+ defaultVariants: {
+ orientation: "horizontal",
+ },
+ }
+)
+
+function ButtonGroup({
+ className,
+ orientation,
+ ...props
+}: React.ComponentProps<"div"> & VariantProps) {
+ return (
+
+ )
+}
+
+function ButtonGroupText({
+ className,
+ render,
+ ...props
+}: useRender.ComponentProps<"div">) {
+ return useRender({
+ defaultTagName: "div",
+ props: mergeProps<"div">(
+ {
+ className: cn(
+ "flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
+ className
+ ),
+ },
+ props
+ ),
+ render,
+ state: {
+ slot: "button-group-text",
+ },
+ })
+}
+
+function ButtonGroupSeparator({
+ className,
+ orientation = "vertical",
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ ButtonGroup,
+ ButtonGroupSeparator,
+ ButtonGroupText,
+ buttonGroupVariants,
+}
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..b033601
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,58 @@
+import { Button as ButtonPrimitive } from "@base-ui/react/button"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
+ outline:
+ "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
+ ghost:
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
+ destructive:
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default:
+ "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ icon: "size-8",
+ "icon-xs":
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
+ "icon-sm":
+ "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
+ "icon-lg": "size-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+function Button({
+ className,
+ variant = "default",
+ size = "default",
+ ...props
+}: ButtonPrimitive.Props & VariantProps) {
+ return (
+
+ )
+}
+
+export { Button, buttonVariants }
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
new file mode 100644
index 0000000..4458dae
--- /dev/null
+++ b/src/components/ui/card.tsx
@@ -0,0 +1,103 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Card({
+ className,
+ size = "default",
+ ...props
+}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
+ return (
+ img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..014f5aa
--- /dev/null
+++ b/src/components/ui/dialog.tsx
@@ -0,0 +1,160 @@
+"use client"
+
+import * as React from "react"
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
+
+function Dialog({ ...props }: DialogPrimitive.Root.Props) {
+ return
+}
+
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
+ return
+}
+
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
+ return
+}
+
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
+ return
+}
+
+function DialogOverlay({
+ className,
+ ...props
+}: DialogPrimitive.Backdrop.Props) {
+ return (
+
+ )
+}
+
+function DialogContent({
+ className,
+ children,
+ showCloseButton = true,
+ ...props
+}: DialogPrimitive.Popup.Props & {
+ showCloseButton?: boolean
+}) {
+ return (
+
+
+
+ {children}
+ {showCloseButton && (
+
+ }
+ >
+
+ Close
+
+ )}
+
+
+ )
+}
+
+function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean
+}) {
+ return (
+
+ {children}
+ {showCloseButton && (
+ }>
+ Close
+
+ )}
+
+ )
+}
+
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
+ return (
+
+ )
+}
+
+function DialogDescription({
+ className,
+ ...props
+}: DialogPrimitive.Description.Props) {
+ return (
+
+ )
+}
+
+export {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
+}
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..9d5ebbd
--- /dev/null
+++ b/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,268 @@
+"use client"
+
+import * as React from "react"
+import { Menu as MenuPrimitive } from "@base-ui/react/menu"
+
+import { cn } from "@/lib/utils"
+import { ChevronRightIcon, CheckIcon } from "lucide-react"
+
+function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
+ return
+}
+
+function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
+ return
+}
+
+function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
+ return
+}
+
+function DropdownMenuContent({
+ align = "start",
+ alignOffset = 0,
+ side = "bottom",
+ sideOffset = 4,
+ className,
+ ...props
+}: MenuPrimitive.Popup.Props &
+ Pick<
+ MenuPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset"
+ >) {
+ return (
+
+
+
+
+
+ )
+}
+
+function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
+ return
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: MenuPrimitive.GroupLabel.Props & {
+ inset?: boolean
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: MenuPrimitive.Item.Props & {
+ inset?: boolean
+ variant?: "default" | "destructive"
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
+ return
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: MenuPrimitive.SubmenuTrigger.Props & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function DropdownMenuSubContent({
+ align = "start",
+ alignOffset = -3,
+ side = "right",
+ sideOffset = 0,
+ className,
+ ...props
+}: React.ComponentProps
) {
+ return (
+
+ )
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ inset,
+ ...props
+}: MenuPrimitive.CheckboxItem.Props & {
+ inset?: boolean
+}) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
+ return (
+
+ )
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ inset,
+ ...props
+}: MenuPrimitive.RadioItem.Props & {
+ inset?: boolean
+}) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: MenuPrimitive.Separator.Props) {
+ return (
+
+ )
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..7d21bab
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,20 @@
+import * as React from "react"
+import { Input as InputPrimitive } from "@base-ui/react/input"
+
+import { cn } from "@/lib/utils"
+
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
+ return (
+
+ )
+}
+
+export { Input }
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
new file mode 100644
index 0000000..74da65c
--- /dev/null
+++ b/src/components/ui/label.tsx
@@ -0,0 +1,20 @@
+"use client"
+
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Label({ className, ...props }: React.ComponentProps<"label">) {
+ return (
+
+ )
+}
+
+export { Label }
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
new file mode 100644
index 0000000..e8021f5
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,201 @@
+"use client"
+
+import * as React from "react"
+import { Select as SelectPrimitive } from "@base-ui/react/select"
+
+import { cn } from "@/lib/utils"
+import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
+
+const Select = SelectPrimitive.Root
+
+function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
+ return (
+
+ )
+}
+
+function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
+ return (
+
+ )
+}
+
+function SelectTrigger({
+ className,
+ size = "default",
+ children,
+ ...props
+}: SelectPrimitive.Trigger.Props & {
+ size?: "sm" | "default"
+}) {
+ return (
+
+ {children}
+
+ }
+ />
+
+ )
+}
+
+function SelectContent({
+ className,
+ children,
+ side = "bottom",
+ sideOffset = 4,
+ align = "center",
+ alignOffset = 0,
+ alignItemWithTrigger = true,
+ ...props
+}: SelectPrimitive.Popup.Props &
+ Pick<
+ SelectPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
+ >) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+function SelectLabel({
+ className,
+ ...props
+}: SelectPrimitive.GroupLabel.Props) {
+ return (
+
+ )
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: SelectPrimitive.Item.Props) {
+ return (
+
+
+ {children}
+
+
+ }
+ >
+
+
+
+ )
+}
+
+function SelectSeparator({
+ className,
+ ...props
+}: SelectPrimitive.Separator.Props) {
+ return (
+
+ )
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+}
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
new file mode 100644
index 0000000..6e1369e
--- /dev/null
+++ b/src/components/ui/separator.tsx
@@ -0,0 +1,25 @@
+"use client"
+
+import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
+
+import { cn } from "@/lib/utils"
+
+function Separator({
+ className,
+ orientation = "horizontal",
+ ...props
+}: SeparatorPrimitive.Props) {
+ return (
+
+ )
+}
+
+export { Separator }
diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx
new file mode 100644
index 0000000..78c0a76
--- /dev/null
+++ b/src/components/ui/sheet.tsx
@@ -0,0 +1,138 @@
+"use client"
+
+import * as React from "react"
+import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
+
+function Sheet({ ...props }: SheetPrimitive.Root.Props) {
+ return
+}
+
+function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {
+ return
+}
+
+function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
+ return
+}
+
+function SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {
+ return
+}
+
+function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
+ return (
+
+ )
+}
+
+function SheetContent({
+ className,
+ children,
+ side = "right",
+ showCloseButton = true,
+ ...props
+}: SheetPrimitive.Popup.Props & {
+ side?: "top" | "right" | "bottom" | "left"
+ showCloseButton?: boolean
+}) {
+ return (
+
+
+
+ {children}
+ {showCloseButton && (
+
+ }
+ >
+
+ Close
+
+ )}
+
+
+ )
+}
+
+function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
+ return (
+
+ )
+}
+
+function SheetDescription({
+ className,
+ ...props
+}: SheetPrimitive.Description.Props) {
+ return (
+
+ )
+}
+
+export {
+ Sheet,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+}
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
new file mode 100644
index 0000000..9280ee5
--- /dev/null
+++ b/src/components/ui/sonner.tsx
@@ -0,0 +1,49 @@
+"use client"
+
+import { useTheme } from "next-themes"
+import { Toaster as Sonner, type ToasterProps } from "sonner"
+import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+
+ ),
+ info: (
+
+ ),
+ warning: (
+
+ ),
+ error: (
+
+ ),
+ loading: (
+
+ ),
+ }}
+ style={
+ {
+ "--normal-bg": "var(--popover)",
+ "--normal-text": "var(--popover-foreground)",
+ "--normal-border": "var(--border)",
+ "--border-radius": "var(--radius)",
+ } as React.CSSProperties
+ }
+ toastOptions={{
+ classNames: {
+ toast: "cn-toast",
+ },
+ }}
+ {...props}
+ />
+ )
+}
+
+export { Toaster }
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
new file mode 100644
index 0000000..abeaced
--- /dev/null
+++ b/src/components/ui/table.tsx
@@ -0,0 +1,116 @@
+"use client"
+
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Table({ className, ...props }: React.ComponentProps<"table">) {
+ return (
+
+ )
+}
+
+function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
+ return (
+
+ )
+}
+
+function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
+ return (
+
+ )
+}
+
+function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
+ return (
+ tr]:last:border-b-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
+ return (
+
+ )
+}
+
+function TableHead({ className, ...props }: React.ComponentProps<"th">) {
+ return (
+
+ )
+}
+
+function TableCell({ className, ...props }: React.ComponentProps<"td">) {
+ return (
+
+ )
+}
+
+function TableCaption({
+ className,
+ ...props
+}: React.ComponentProps<"caption">) {
+ return (
+
+ )
+}
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..8ee8054
--- /dev/null
+++ b/src/components/ui/tabs.tsx
@@ -0,0 +1,82 @@
+"use client"
+
+import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+function Tabs({
+ className,
+ orientation = "horizontal",
+ ...props
+}: TabsPrimitive.Root.Props) {
+ return (
+
+ )
+}
+
+const tabsListVariants = cva(
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function TabsList({
+ className,
+ variant = "default",
+ ...props
+}: TabsPrimitive.List.Props & VariantProps) {
+ return (
+
+ )
+}
+
+function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
+ return (
+
+ )
+}
+
+function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
+ return (
+
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
diff --git a/src/components/ui/toggle-group.tsx b/src/components/ui/toggle-group.tsx
new file mode 100644
index 0000000..1e4b785
--- /dev/null
+++ b/src/components/ui/toggle-group.tsx
@@ -0,0 +1,89 @@
+"use client"
+
+import * as React from "react"
+import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
+import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
+import { type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+import { toggleVariants } from "@/components/ui/toggle"
+
+const ToggleGroupContext = React.createContext<
+ VariantProps & {
+ spacing?: number
+ orientation?: "horizontal" | "vertical"
+ }
+>({
+ size: "default",
+ variant: "default",
+ spacing: 2,
+ orientation: "horizontal",
+})
+
+function ToggleGroup({
+ className,
+ variant,
+ size,
+ spacing = 2,
+ orientation = "horizontal",
+ children,
+ ...props
+}: ToggleGroupPrimitive.Props &
+ VariantProps & {
+ spacing?: number
+ orientation?: "horizontal" | "vertical"
+ }) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+function ToggleGroupItem({
+ className,
+ children,
+ variant = "default",
+ size = "default",
+ ...props
+}: TogglePrimitive.Props & VariantProps) {
+ const context = React.useContext(ToggleGroupContext)
+
+ return (
+
+ {children}
+
+ )
+}
+
+export { ToggleGroup, ToggleGroupItem }
diff --git a/src/components/ui/toggle.tsx b/src/components/ui/toggle.tsx
new file mode 100644
index 0000000..555637b
--- /dev/null
+++ b/src/components/ui/toggle.tsx
@@ -0,0 +1,45 @@
+"use client"
+
+import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const toggleVariants = cva(
+ "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ variant: {
+ default: "bg-transparent",
+ outline: "border border-input bg-transparent hover:bg-muted",
+ },
+ size: {
+ default:
+ "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
+ lg: "h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+function Toggle({
+ className,
+ variant = "default",
+ size = "default",
+ ...props
+}: TogglePrimitive.Props & VariantProps) {
+ return (
+
+ )
+}
+
+export { Toggle, toggleVariants }
diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..69e8a82
--- /dev/null
+++ b/src/components/ui/tooltip.tsx
@@ -0,0 +1,66 @@
+"use client"
+
+import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
+
+import { cn } from "@/lib/utils"
+
+function TooltipProvider({
+ delay = 0,
+ ...props
+}: TooltipPrimitive.Provider.Props) {
+ return (
+
+ )
+}
+
+function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
+ return
+}
+
+function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
+ return
+}
+
+function TooltipContent({
+ className,
+ side = "top",
+ sideOffset = 4,
+ align = "center",
+ alignOffset = 0,
+ children,
+ ...props
+}: TooltipPrimitive.Popup.Props &
+ Pick<
+ TooltipPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset"
+ >) {
+ return (
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/src/hooks/use-media-query.ts b/src/hooks/use-media-query.ts
new file mode 100644
index 0000000..77d0289
--- /dev/null
+++ b/src/hooks/use-media-query.ts
@@ -0,0 +1,26 @@
+"use client";
+
+import * as React from "react";
+
+/**
+ * Liest eine Media Query ohne Hydration-Mismatch: Auf dem Server ist das Ergebnis
+ * immer `false`, der Client aktualisiert direkt nach der Hydration.
+ */
+export function useMediaQuery(query: string) {
+ const subscribe = React.useCallback(
+ (onChange: () => void) => {
+ const list = window.matchMedia(query);
+ list.addEventListener("change", onChange);
+ return () => list.removeEventListener("change", onChange);
+ },
+ [query],
+ );
+
+ return React.useSyncExternalStore(
+ subscribe,
+ () => window.matchMedia(query).matches,
+ () => false,
+ );
+}
+
+export const useIsMobile = () => useMediaQuery("(max-width: 767px)");
diff --git a/src/lib/data.ts b/src/lib/data.ts
new file mode 100644
index 0000000..5d7a01b
--- /dev/null
+++ b/src/lib/data.ts
@@ -0,0 +1,133 @@
+import {
+ UNDELIVERED_AFTER_MS,
+ type Order,
+ type OrderStatus,
+ type OrderType,
+ type PaymentMethod,
+ type Restaurant,
+} from "./types";
+
+const restaurants: Restaurant[] = [
+ {
+ name: "Muster Ristorante",
+ city: "Taben-Rodt",
+ hours: "10:00 bis 23:00",
+ phone1: "+49 6582 123456",
+ phone2: "+49 6582 123457",
+ mobile: "+49 171 2223344",
+ orderUrl: "https://order.speisekarte24.de/muster-ristorante",
+ },
+ {
+ name: "Pizzeria Da Vinci",
+ city: "Trier",
+ hours: "11:00 bis 22:30",
+ phone1: "+49 651 998877",
+ mobile: "+49 160 5544332",
+ orderUrl: "https://order.speisekarte24.de/da-vinci",
+ },
+ {
+ name: "Sushi Yama",
+ city: "Saarbrücken",
+ hours: "12:00 bis 23:00",
+ phone1: "+49 681 445566",
+ phone2: "+49 681 445567",
+ mobile: "+49 175 1112233",
+ orderUrl: "https://order.speisekarte24.de/sushi-yama",
+ },
+ {
+ name: "Burger Station",
+ city: "Konz",
+ hours: "11:30 bis 21:00",
+ phone1: "+49 6501 334455",
+ mobile: "+49 152 9988776",
+ orderUrl: "https://order.speisekarte24.de/burger-station",
+ },
+ {
+ name: "Athen Grill",
+ city: "Wittlich",
+ hours: "17:00 bis 23:30",
+ phone1: "+49 6571 220011",
+ orderUrl: "https://order.speisekarte24.de/athen-grill",
+ },
+];
+
+const customers = [
+ { name: "Test Tester", email: "agentur@speisekarte24.de", phone: "+49 170 1234567" },
+ { name: "Anna Berger", email: "anna.berger@example.com", phone: "+49 151 2345678" },
+ { name: "Murat Yilmaz", email: "m.yilmaz@example.com", phone: "+49 176 3456789" },
+ { name: "Sophie Klein", email: "sophie.klein@example.com", phone: "+49 152 4567890" },
+ { name: "Lukas Weber", email: "lukas.weber@example.com", phone: "+49 160 5678901" },
+ { name: "Nina Hoffmann", email: "nina.h@example.com", phone: "+49 171 6789012" },
+ { name: "Jonas Krämer", email: "j.kraemer@example.com", phone: "+49 175 7890123" },
+ { name: "Elif Demir", email: "elif.demir@example.com", phone: "+49 157 8901234" },
+];
+
+/** Status für Bestellungen, die bereits bearbeitet wurden. */
+const handledStatuses: OrderStatus[] = [
+ "uebermittelt",
+ "uebermittelt",
+ "uebermittelt",
+ "telefonisch",
+ "telefonisch",
+ "rueckruf",
+ "storniert",
+ "fake",
+];
+
+/**
+ * Ältere Bestellungen mit diesem Index bleiben `neu` und kippen dadurch über die
+ * 15-Minuten-Regel auf "Nicht übermittelt" – bewusst nur eine Handvoll.
+ */
+const undeliveredIndexes = new Set([4, 11, 23]);
+
+const types: OrderType[] = ["vorbestellung", "direktanruf"];
+const payments: PaymentMethod[] = ["bar", "ec", "paypal", "kreditkarte"];
+
+/** Deterministischer PRNG, damit Server- und Client-Render identisch sind. */
+function seeded(seed: number) {
+ let s = seed;
+ return () => {
+ s = (s * 1664525 + 1013904223) % 4294967296;
+ return s / 4294967296;
+ };
+}
+
+/**
+ * Erzeugt Demo-Bestellungen relativ zu `now`, damit die jüngsten Aufträge innerhalb
+ * des 15-Minuten-Fensters liegen und ältere als nicht übermittelt gelten.
+ */
+export function createOrders(now: number, count = 42): Order[] {
+ const rand = seeded(20260804);
+
+ return Array.from({ length: count }, (_, i) => {
+ const ageMinutes = i * 6 + Math.floor(rand() * 4);
+ const receivedAt = new Date(now - ageMinutes * 60_000);
+ const dueAt = new Date(receivedAt.getTime() + (20 + Math.floor(rand() * 55)) * 60_000);
+ const fresh = ageMinutes * 60_000 < UNDELIVERED_AFTER_MS;
+ const handled = handledStatuses[Math.floor(rand() * handledStatuses.length)];
+ const open = fresh || undeliveredIndexes.has(i);
+ // Bearbeitete Bestellungen wurden innerhalb der Eskalationsfrist bestätigt.
+ const confirmedAt = open
+ ? undefined
+ : new Date(receivedAt.getTime() + (1 + Math.floor(rand() * 12)) * 60_000).toISOString();
+
+ return {
+ id: `ord_${1000 + i}`,
+ number: count - i,
+ // Frische Bestellungen dürfen offen sein, ältere nur die ausgewählten drei.
+ status: open ? "neu" : handled,
+ type: types[Math.floor(rand() * types.length)],
+ restaurant: restaurants[Math.floor(rand() * restaurants.length)],
+ customer: customers[Math.floor(rand() * customers.length)],
+ receivedAt: receivedAt.toISOString(),
+ dueAt: dueAt.toISOString(),
+ total: Math.round((6 + rand() * 60) * 100) / 100,
+ itemCount: 1 + Math.floor(rand() * 7),
+ payment: payments[Math.floor(rand() * payments.length)],
+ pdfUrl: `/bestellungen/ord_${1000 + i}.pdf`,
+ externalUrl: `https://backoffice.speisekarte24.de/bestellungen/${1000 + i}`,
+ confirmedAt,
+ events: [],
+ } satisfies Order;
+ });
+}
diff --git a/src/lib/format.ts b/src/lib/format.ts
new file mode 100644
index 0000000..b682f50
--- /dev/null
+++ b/src/lib/format.ts
@@ -0,0 +1,12 @@
+const currency = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" });
+const time = new Intl.DateTimeFormat("de-DE", { hour: "2-digit", minute: "2-digit" });
+const date = new Intl.DateTimeFormat("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" });
+
+export const formatCurrency = (value: number) => currency.format(value);
+export const formatTime = (iso: string) => time.format(new Date(iso));
+export const formatDate = (iso: string) => date.format(new Date(iso));
+
+/** "tel:" bzw. "https://wa.me/" Links brauchen die Nummer ohne Leer- und Sonderzeichen. */
+export const telHref = (phone: string) => `tel:${phone.replace(/[^\d+]/g, "")}`;
+export const whatsAppHref = (phone: string) =>
+ `https://wa.me/${phone.replace(/[^\d]/g, "")}`;
diff --git a/src/lib/timeline.ts b/src/lib/timeline.ts
new file mode 100644
index 0000000..004bc2e
--- /dev/null
+++ b/src/lib/timeline.ts
@@ -0,0 +1,151 @@
+import {
+ ATTEMPT_COUNT,
+ ATTEMPT_INTERVAL_MS,
+ UNDELIVERED_AFTER_MS,
+ type Order,
+ type OrderAction,
+} from "./types";
+
+export type StepState =
+ /** Ist passiert. */
+ | "done"
+ /** Steht jetzt an und wartet auf eine Bearbeiterin. */
+ | "due"
+ /** Kommt später automatisch. */
+ | "pending"
+ /** Entfällt, weil der Gastronom vorher bestätigt hat. */
+ | "skipped";
+
+export type TimelineStep = {
+ id: string;
+ label: string;
+ /** Kurzform für die Tabellenspalte. */
+ short: string;
+ description?: string;
+ /** Zeitpunkt des Ereignisses bzw. geplanter Zeitpunkt. */
+ at?: number;
+ state: StepState;
+ /** Eskalationsstufe – wird rot dargestellt. */
+ danger?: boolean;
+ /** Manuelle Schritte tragen die Aktion, die der Button auslöst. */
+ action?: OrderAction;
+};
+
+/**
+ * Eskalationskette einer Bestellung: drei automatische Übermittlungsversuche, danach der
+ * Tag "Nicht übermittelt" und die manuellen Stufen Voice-Message, Direktanruf und SOS.
+ */
+export function buildTimeline(order: Order, now: number): TimelineStep[] {
+ const received = Date.parse(order.receivedAt);
+ const confirmed = order.confirmedAt ? Date.parse(order.confirmedAt) : null;
+ const taggedAt = received + UNDELIVERED_AFTER_MS;
+ const eventAt = (type: OrderAction) => {
+ const event = order.events.find((e) => e.type === type);
+ return event ? Date.parse(event.at) : null;
+ };
+
+ const steps: TimelineStep[] = [
+ {
+ id: "ordered",
+ label: order.type === "vorbestellung" ? "Vorbestellung geplant" : "Bestellung eingegangen",
+ short: order.type === "vorbestellung" ? "Geplant" : "Eingegangen",
+ description:
+ order.type === "vorbestellung"
+ ? `Gewünscht ${new Date(order.dueAt).toLocaleTimeString("de-DE", {
+ hour: "2-digit",
+ minute: "2-digit",
+ })} Uhr`
+ : undefined,
+ at: received,
+ state: "done",
+ },
+ ];
+
+ for (let n = 1; n <= ATTEMPT_COUNT; n++) {
+ const at = received + (n - 1) * ATTEMPT_INTERVAL_MS;
+ steps.push({
+ id: `attempt_${n}`,
+ label: `${n}. Übermittlung an Gastronom`,
+ short: `${n}. Übermittlung`,
+ description: confirmed && confirmed <= at ? "Entfällt – bereits bestätigt" : undefined,
+ at,
+ state: confirmed && confirmed <= at ? "skipped" : now >= at ? "done" : "pending",
+ });
+ }
+
+ if (confirmed) {
+ steps.push({
+ id: "confirmed",
+ label: "Gastronom hat bestätigt",
+ short: "Bestätigt",
+ at: confirmed,
+ state: "done",
+ });
+ return steps;
+ }
+
+ const tagged = now >= taggedAt;
+ steps.push({
+ id: "tagged",
+ label: 'Tag "Nicht übermittelt"',
+ short: "Nicht übermittelt",
+ description: "15 Minuten ohne Reaktion",
+ at: taggedAt,
+ state: tagged ? "done" : "pending",
+ danger: true,
+ });
+
+ const manual: {
+ id: string;
+ label: string;
+ short: string;
+ action: OrderAction;
+ danger?: boolean;
+ }[] = [
+ {
+ id: "voice",
+ label: "Manuelle Voice-Message an Gastronom",
+ short: "Voice-Message",
+ action: "gastronom_voice",
+ },
+ {
+ id: "call",
+ label: "Direktanruf beim Gastronom",
+ short: "Direktanruf",
+ action: "gastronom_anruf",
+ },
+ {
+ id: "sos",
+ label: "SOS: Stornieren & Gastronom für heute schließen",
+ short: "SOS",
+ action: "sos",
+ danger: true,
+ },
+ ];
+
+ let previousDone = tagged;
+ for (const step of manual) {
+ const at = eventAt(step.action);
+ steps.push({
+ ...step,
+ at: at ?? undefined,
+ state: at ? "done" : previousDone ? "due" : "pending",
+ });
+ previousDone = at !== null;
+ }
+
+ return steps;
+}
+
+/**
+ * Der Punkt, an dem die Bestellung gerade steht: der fällige Schritt, sonst der zuletzt
+ * erledigte. Treibt die Verlaufsspalte der Tabelle.
+ */
+export function currentStep(order: Order, now: number): TimelineStep {
+ const steps = buildTimeline(order, now);
+ const due = steps.find((step) => step.state === "due");
+ if (due) return due;
+
+ const done = steps.filter((step) => step.state === "done");
+ return done[done.length - 1] ?? steps[0];
+}
diff --git a/src/lib/types.ts b/src/lib/types.ts
new file mode 100644
index 0000000..e5c6a7f
--- /dev/null
+++ b/src/lib/types.ts
@@ -0,0 +1,109 @@
+export type OrderStatus =
+ | "neu"
+ | "uebermittelt"
+ | "telefonisch"
+ | "nicht_uebermittelt"
+ | "rueckruf"
+ | "storniert"
+ | "fake";
+
+export type OrderType = "vorbestellung" | "direktanruf";
+
+/** Alles, was eine Bearbeiterin an einer Bestellung auslösen kann. */
+export type OrderAction =
+ | "uebermittelt"
+ | "gastronom_voice"
+ | "gastronom_anruf"
+ | "kunde_anrufen"
+ | "nicht_uebermittelt"
+ | "rueckruf"
+ | "storno"
+ | "fake"
+ | "stornieren"
+ | "sos"
+ | "telefonisch_uebermittelt";
+
+/** Protokolleintrag einer ausgelösten Aktion, treibt die Timeline. */
+export type OrderEvent = { type: OrderAction; at: string };
+
+export type PaymentMethod = "bar" | "ec" | "paypal" | "kreditkarte";
+
+export type Restaurant = {
+ name: string;
+ city: string;
+ /** Öffnungszeiten, z. B. "10:00 bis 23:00" */
+ hours: string;
+ phone1: string;
+ phone2?: string;
+ mobile?: string;
+ orderUrl: string;
+};
+
+export type Customer = {
+ name: string;
+ email: string;
+ phone: string;
+};
+
+export type Order = {
+ id: string;
+ /** Fortlaufende Bestellnummer, wird in der Liste als erste Spalte gezeigt */
+ number: number;
+ status: OrderStatus;
+ type: OrderType;
+ restaurant: Restaurant;
+ customer: Customer;
+ /** Zeitpunkt des Bestelleingangs, ISO-String */
+ receivedAt: string;
+ /** Gewünschte Liefer- bzw. Abholzeit, ISO-String */
+ dueAt: string;
+ total: number;
+ itemCount: number;
+ payment: PaymentMethod;
+ pdfUrl: string;
+ /** Bestellung im externen Backoffice, öffnet in neuem Tab. */
+ externalUrl: string;
+ note?: string;
+ /** Zeitpunkt, zu dem der Gastronom die Bestellung bestätigt hat. */
+ confirmedAt?: string;
+ /** Manuell ausgelöste Schritte, ältester zuerst. */
+ events: OrderEvent[];
+};
+
+export const STATUS_LABEL: Record = {
+ neu: "Neu",
+ uebermittelt: "Übermittelt",
+ telefonisch: "Telefonisch übermittelt",
+ nicht_uebermittelt: "Nicht übermittelt",
+ rueckruf: "Rückrufhinweis",
+ storniert: "Storniert",
+ fake: "Fake",
+};
+
+export const TYPE_LABEL: Record = {
+ vorbestellung: "Vorbestellung",
+ direktanruf: "Direktanruf",
+};
+
+export const PAYMENT_LABEL: Record = {
+ bar: "Bar",
+ ec: "EC-Karte",
+ paypal: "PayPal",
+ kreditkarte: "Kreditkarte",
+};
+
+/** Abstand zwischen den drei automatischen Übermittlungsversuchen. */
+export const ATTEMPT_INTERVAL_MS = 5 * 60 * 1000;
+export const ATTEMPT_COUNT = 3;
+
+/** Nach dieser Zeit ohne Bearbeitung gilt eine Bestellung als nicht übermittelt. */
+export const UNDELIVERED_AFTER_MS = 15 * 60 * 1000;
+
+/**
+ * Eine unbearbeitete Bestellung kippt nach {@link UNDELIVERED_AFTER_MS} automatisch auf
+ * `nicht_uebermittelt`. Sobald jemand eine Aktion ausgelöst hat, bleibt der echte Status stehen.
+ */
+export function effectiveStatus(order: Order, now: number): OrderStatus {
+ const overdue = now - new Date(order.receivedAt).getTime() >= UNDELIVERED_AFTER_MS;
+ return order.status === "neu" && overdue ? "nicht_uebermittelt" : order.status;
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..bd0c391
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}