diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddce69b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +.astro/ diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..91fc975 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,21 @@ +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + // Relative asset URLs, so the site works wherever it is hosted, e.g. https://berlin.ccc.de/kik/ + build: { format: 'file', assetsPrefix: '.', inlineStylesheets: 'never' }, + compressHTML: false, + vite: { + // The pages' styles, which Astro bundles while building the pages, readable rather than minified + build: { cssMinify: false, rolldownOptions: { output: { assetFileNames: 'styles.css' } } }, + environments: { + client: { + build: { + rolldownOptions: { + // The page's script and the terminal it loads + output: { entryFileNames: 'loader.js', chunkFileNames: 'terminal.js' }, + }, + }, + }, + }, + }, +}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9452d21 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3716 @@ +{ + "name": "kik-website", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kik-website", + "dependencies": { + "@noble/ciphers": "^2.4.0", + "@noble/curves": "^2.4.0", + "@noble/hashes": "^2.4.0", + "@xterm/addon-web-links": "^0.12.0", + "@xterm/xterm": "^6.0.0", + "astro": "^7.4.2" + } + }, + "node_modules/@astrojs/compiler-binding": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.5.2.tgz", + "integrity": "sha512-lEn76+0JcMQ5RDXU0wSMWJg2ZppiZvSULpghC29cfv4o9bhvWFDbQjsCtvjjXN9iVLFQ7fL3wTR2L2UU13mP8g==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.5.2", + "@astrojs/compiler-binding-darwin-arm64": "0.5.2", + "@astrojs/compiler-binding-darwin-x64": "0.5.2", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.5.2", + "@astrojs/compiler-binding-linux-arm64-musl": "0.5.2", + "@astrojs/compiler-binding-linux-x64-gnu": "0.5.2", + "@astrojs/compiler-binding-linux-x64-musl": "0.5.2", + "@astrojs/compiler-binding-wasm32-wasi": "0.5.2", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.5.2", + "@astrojs/compiler-binding-win32-x64-msvc": "0.5.2" + } + }, + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.5.2.tgz", + "integrity": "sha512-kckIxon6Rm/Bxzh9mGPYpRRqUbToUQoHptCmpMmE+Yt0Xumq8CqrKUidyYhrBsrHVO7bxuRzzWUUqvpf+iYceQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.5.2.tgz", + "integrity": "sha512-1ZG5Ar3dD8HtodX9XH1mRmE0qBXZlvjYXSFfpgFwocqfWnvhFuqtGUNseL8wgfImiRMztIjpQqlogQFQQtgiag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.5.2.tgz", + "integrity": "sha512-+kl35S7hiHJ2cb7eujwEsPFYYuSgE11uEE2Z20lAJ+undpgulMcW+weQqFPOSSZccEKHOiLIY+kQHkb4e4092w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.5.2.tgz", + "integrity": "sha512-BqlR0EHNQLPLwgL9+xogjsAc7zGf0cHho2CPdhv0P1yqbVMwGVaGAqrANP6VYAXCqSC43AF4Czcxc2n+oqdesg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.5.2.tgz", + "integrity": "sha512-GRGyby3AZWw5d6JQzidyxPyvGgHWsSusrpgKyFVpDTKctABF7L3Pd5V1cRJbV36/rcu+Eh292/wL7pF7MkmGkQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.5.2.tgz", + "integrity": "sha512-9XAqGTMQAtIslMsjK3xdyY6OI9d59OZqcLBB6pvD/DcoR0daYswfrKx2azdDERDY4AqAnWPC7odVM1BmxYv3Vw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.5.2.tgz", + "integrity": "sha512-jOViewGeTh9bSfS8vK72ECxoy2yvmA+Pd/ZcEvBI5c7+7IcfHwZ5qA4L9fRYuOhSrAifvQ2dV4vm1XAtloaWBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.5.2.tgz", + "integrity": "sha512-Z7p64doar1uvR5C9Xs6j1CV9lGlPVQX7OQ2aAtZ/xKC5aGS6GB13nyc2UfQXTQLvZrvVwsyaflTQy6ziY5Bekw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "^1.2.5" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.5.2.tgz", + "integrity": "sha512-Tr13bh+ahTWsjXjzctK7pFpWV+dUU4FtBfETlR7gO+ueex0F+RDch7eRr0YfKysaRhk9tWm14lsCJ5uWyFPNHQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.5.2.tgz", + "integrity": "sha512-SfKkI+jOQYLh6wojPvVPV0lFfQnxisweN9B+qCzRvZp7DHAuGif8Y0WcC5PUgN4jb8VKy57LggQDtggR46Du1g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-rs": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.5.2.tgz", + "integrity": "sha512-IvwYLB8t1M86rKO4oPdBi9GP4gzXcgrVlNgocjwos1jeeUuEIV8d9Crn1PvYD/5IKteWOxpIHomf7e8iYlkE+Q==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.5.2" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.13.0.tgz", + "integrity": "sha512-20jxQqnSmpskcGyad7N5l6Xf1gz0UCa6lNde44bEBdaXGpncEYfAZJ142r2ZgzBaG4dUyzGmhqZWv1INU2eiHQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "picomatch": "^4.0.7", + "retext-smartypants": "^6.2.0", + "shiki": "^4.5.0", + "smol-toml": "^1.9.1", + "unified": "^11.0.5", + "yaml": "^2.9.1" + } + }, + "node_modules/@astrojs/markdown-satteri": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.5.tgz", + "integrity": "sha512-0IeGdoFbv0f+442KJhYS44Wg8F3MuHmRsxIEYuFyqkjRubc6dPBFZ7azor5t4AeXLQoT5A5h9HyViKpd70Dl9w==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.13.0", + "@astrojs/prism": "4.1.1", + "github-slugger": "^2.0.0", + "satteri": "^0.10.5" + } + }, + "node_modules/@astrojs/prism": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.1.1.tgz", + "integrity": "sha512-sXlAXJX6t4QfuLg+CuCDzpg7NoxWcyb4paFprgtFppLeisCBmh935h+tJ5CWXfsXEoW2IDy/ihbRMtiu28Chjw==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": ">=22.23.4" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.4.1.tgz", + "integrity": "sha512-SMkvMsGOpM0FMAoT5pzhgI3LZC0JSPWf7Evwop+fZ3N6UkusPM7lI+sOJjMNI5OJrVoiei1/AGo1cY7sikTc5A==", + "license": "MIT", + "dependencies": { + "ci-info": "^4.4.0", + "dset": "^3.1.4", + "is-docker": "^4.0.0", + "package-manager-detector": "^1.9.0" + }, + "engines": { + "node": ">=22.23.4" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.11.tgz", + "integrity": "sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "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==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.11.tgz", + "integrity": "sha512-OZ6+oaK7GMyg3IfCpj8JOmn8n+w2rJbDT0LLfVDTLb1ZFeKDh3AiNELgCMUw175IJHSkLl74hG0M0VLsvx+gag==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.11" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.11.tgz", + "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.11", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@clack/core": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz", + "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@clack/prompts": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz", + "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.5.1", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", + "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@noble/ciphers": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.4.0.tgz", + "integrity": "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", + "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.4.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz", + "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz", + "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz", + "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz", + "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz", + "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz", + "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz", + "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz", + "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz", + "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz", + "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz", + "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz", + "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz", + "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz", + "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz", + "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.5.0.tgz", + "integrity": "sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.5.0.tgz", + "integrity": "sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.5.0.tgz", + "integrity": "sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.5.0.tgz", + "integrity": "sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.5.0.tgz", + "integrity": "sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.5.0.tgz", + "integrity": "sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.5.0.tgz", + "integrity": "sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.1.0.tgz", + "integrity": "sha512-cVBuhDQjBZaNMTwBquYfPydrUP+E3hE6oYGasx8h6ZrODIM7/r+gxLDXdd66oszbrggZHEntdE6j+5gYIVyMWQ==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/@xterm/addon-web-links": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.12.0.tgz", + "integrity": "sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==", + "license": "MIT" + }, + "node_modules/@xterm/xterm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz", + "integrity": "sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==", + "license": "MIT", + "workspaces": [ + "addons/*" + ] + }, + "node_modules/am-i-vibing": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.5.0.tgz", + "integrity": "sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==", + "license": "MIT", + "dependencies": { + "process-ancestry": "^0.1.0" + }, + "bin": { + "am-i-vibing": "dist/cli.mjs" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/astro": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.4.2.tgz", + "integrity": "sha512-FAH4cdDlFaVnQGjazLTEIC5vJqGlo5XANc1wIbzQHIqAjJTll/RWTUs+SPNW1JdezG4YGxMZllaE5A41T2kzhA==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-rs": "^0.5.1", + "@astrojs/internal-helpers": "0.13.0", + "@astrojs/markdown-satteri": "0.4.5", + "@astrojs/telemetry": "3.4.1", + "@capsizecss/unpack": "^4.0.1", + "@clack/prompts": "^1.8.1", + "@oslojs/encoding": "^1.1.0", + "am-i-vibing": "^0.5.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "ci-info": "^4.4.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^2.0.0", + "cookie": "^2.0.1", + "devalue": "^6.0.2", + "diff": "^9.0.0", + "dset": "^3.1.4", + "es-module-lexer": "^3.0.3", + "flattie": "^1.1.1", + "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.6", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.3.0", + "jsonc-parser": "^3.3.1", + "magic-string": "^1.4.3", + "magicast": "^0.5.5", + "mrmime": "^2.0.1", + "neotraverse": "^1.0.1", + "obug": "^3.0.0", + "p-limit": "^7.3.3", + "p-queue": "^9.3.5", + "package-manager-detector": "^1.9.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.7", + "rolldown": "^1.2.13", + "shiki": "^4.5.0", + "smol-toml": "^1.9.1", + "svgo": "^4.1.0", + "tinyclip": "^1.0.3", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "tinyps": "^0.5.0", + "ultrahtml": "^1.7.0", + "unifont": "^1.0.3", + "unstorage": "^1.17.5", + "verkit": "^0.5.0", + "vite": "^8.3.4", + "vitefu": "^1.1.3", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^22.0.0", + "zod": "^4.6.6" + }, + "bin": { + "astro": "bin/astro.mjs" + }, + "engines": { + "node": ">=22.23.4", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.35.4" + }, + "peerDependencies": { + "@astrojs/markdown-remark": "^7.3.0" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-remark": { + "optional": true + } + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/common-ancestor-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", + "license": "MIT" + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-6.0.3.tgz", + "integrity": "sha512-3woMEITftG1wKeO/4d/QXH1DVKctTSZg3jNGPpjp9hNr5Hos8MCFF5McTML5ZtgKDObm2R591B0spRp2IVernA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-3.0.4.tgz", + "integrity": "sha512-BldNY5mwkVu+cQ5Ymn3e6hB9Sx8XHx4ZevWbiUyZbfKxJxYO27Hf0wfzkxIaD5CAJMaGl3YspKELj0ff/7nCMA==", + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "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/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fnv1a-64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fnv1a-64/-/fnv1a-64-0.1.2.tgz", + "integrity": "sha512-mJbcILTPybAR1jdOwt/lVv8N2cffeJFFP+gVbSAwLEx1ujXH27RpPd8Rokec/KX9c76UYIB6Co+H4lQzxPnJfA==", + "license": "MIT" + }, + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.2" + } + }, + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", + "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.6.tgz", + "integrity": "sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "engines": { + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "license": "BSD-2-Clause" + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-docker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/magicast": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neotraverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/p-limit": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.5.tgz", + "integrity": "sha512-Lki/zhXFVmDhesBUn/yHRLW9Bte7mE7xoFHzTR8sIomV7a2z+LxYAPkGvdfidNiu4fKSfjtawixxSHcZci5QcQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", + "license": "MIT" + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rolldown": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz", + "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.155.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.15", + "@rolldown/binding-android-arm64": "1.2.15", + "@rolldown/binding-darwin-arm64": "1.2.15", + "@rolldown/binding-darwin-x64": "1.2.15", + "@rolldown/binding-freebsd-x64": "1.2.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", + "@rolldown/binding-linux-arm64-gnu": "1.2.15", + "@rolldown/binding-linux-arm64-musl": "1.2.15", + "@rolldown/binding-linux-ppc64-gnu": "1.2.15", + "@rolldown/binding-linux-s390x-gnu": "1.2.15", + "@rolldown/binding-linux-x64-gnu": "1.2.15", + "@rolldown/binding-linux-x64-musl": "1.2.15", + "@rolldown/binding-openharmony-arm64": "1.2.15", + "@rolldown/binding-win32-arm64-msvc": "1.2.15", + "@rolldown/binding-win32-x64-msvc": "1.2.15" + } + }, + "node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "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", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shiki": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.5.0.tgz", + "integrity": "sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.5.0", + "@shikijs/engine-javascript": "4.5.0", + "@shikijs/engine-oniguruma": "4.5.0", + "@shikijs/langs": "4.5.0", + "@shikijs/themes": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "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/smol-toml": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.1.tgz", + "integrity": "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/std-env": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", + "license": "MIT" + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/svgo": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^6.0.0", + "css-tree": "^3.0.1", + "css-what": "^7.0.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "1.6.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinyclip": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", + "license": "MIT", + "engines": { + "node": "^16.14.0 || >= 17.3.0" + } + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyps": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/tinyps/-/tinyps-0.5.1.tgz", + "integrity": "sha512-B6Ykif5HflC3AdDkS4Zst/2muYVfeXoVMy+KorqH80s/1x4vunIORpNySH681X7fjj+dFM9MDKD6/Hsccjb87Q==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz", + "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", + "license": "MIT" + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.12.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.12.3.tgz", + "integrity": "sha512-+fdndUTwBP86cVjihTp21hZHo7d6oj1c/47XPA3lL8mM0XHs+C4EkcjmgRsFnFk2f/UONGDy9ItBItmXsLOQHw==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unifont": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-1.0.3.tgz", + "integrity": "sha512-XGnEwj5sWdCbiBX01mWLSBncS0yMRjnLygau3IfdOlfjMacNIQvTGW4VH7pWBq+gGWArfSef/CensMLjMmIr/A==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "fnv1a-64": "^0.1.2", + "std-env": "^4.2.0", + "undici": "^8.0.0" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.2.0.tgz", + "integrity": "sha512-fpsYs/VVoZxfGY9/j3FQpZmN8wdLJaV1Pt38AaJNZu9uKIHcFU3halCdBveEq1HGKO1OEfJY65w1zvoFV1b3qQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.1.0.tgz", + "integrity": "sha512-vKXxz6O38sKDj1mtx/k2cWvkkFBuYGx6uGrlzBkVeWCRF/F8sdI0j3Wbkz/5rVNRRuVc8UrgRdbCxNhmYXgP3w==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unstorage": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.6.tgz", + "integrity": "sha512-gjKtcmn/KwZuJZO9o2sc0esAQnhmTw0LviDHwevTXbJMYs0dRTp8ZEEWXHU0vTpzbN3cA0yxlTeyXssMp3zDqw==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.11", + "lru-cache": "^11.5.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.4" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1d631fc --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "kik-website", + "type": "module", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@noble/ciphers": "^2.4.0", + "@noble/curves": "^2.4.0", + "@noble/hashes": "^2.4.0", + "@xterm/addon-web-links": "^0.12.0", + "@xterm/xterm": "^6.0.0", + "astro": "^7.4.2" + } +} diff --git a/logo.png b/public/logo.png similarity index 100% rename from logo.png rename to public/logo.png diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..10b4a89 --- /dev/null +++ b/server/README.md @@ -0,0 +1,114 @@ +# The shell server + +The website's terminal connects to a shell server, whose `root` user logs in at `wss://web.nowhere.wirs.ing` and +gets a shell on the box. + +## The security model + +The box is an isolated, disposable VPS at a random hoster. We assume that it can be compromised and that this is +acceptable: the worst case is that the gimmick on the website stops working. Nothing else is on the box. The +website and the websocket bridge that carries the connection run on other servers, so a compromised shell server +cannot get at them. + +The `root` user on the box is a normal Windows account without administrator rights. It may do a lot of things +there, including things we did not plan for. We do not try to contain it and we do not try to undo what it does. +We only keep the basic user journey working. + +## What we keep working + +Anything that breaks the following user journey is not acceptable: + +- The user can connect with the SSH key as `root`. +- The prompt: `root@khaos-im-kiez:~#`, which `~/.zsh/.zshrc` sets. +- The home directory the user ends up in: `/home/root`. They cannot change where it is, and they cannot delete it. +- `cat README`, `cat README.en`, `cat CODE_OF_CONDUCT` and `cat CODE_OF_CONDUCT.en` always work. The four files + are always there and always regular text files. + +So in summary running `ssh root@nowhere.wirs.ing cat README` must always succeed and display the contents of the file. + +Anything thats not specified above (like the content of README for example) is NOT part of the user journey. + +## What we do not keep working + +As long as the user story above does not break, we do not guarantee the functionality of anything else on the server. However the cleanup task should still try to best-effort restore everything to a working condition. + +## Packages + +The root user owns the whole MSYS2 installation and can install packages with pacman. That means they can also +replace or delete the very programs the login needs. So the sshd, the login shell `zsh` and `cat` are kept as a +second, protected copy in `C:\msys2\opt\kik`, which only SYSTEM and the administrators may write. The sshd runs as +SYSTEM from that copy and the login shell is that copy's `zsh`, with `/opt/kik` first on the path, so the journey +keeps working no matter what the user does to their own `/usr/bin`. Replacing `/usr/bin/sshd` cannot touch the +running server, so the key on the website still never grants administrator access. + +The copy has to be the *same* MSYS2 installation, not a second one: `C:\msys2\opt\kik` is two levels below +`C:\msys2`, so its runtime resolves the same root and the login shell and the user's own tools share one cygwin +runtime. A separate installation does not work - two runtimes in one process tree corrupt each other's file +descriptors and pacman cannot even lock its database. + +The runtime itself is not among the protected copies. A program and the shell that starts it have to use the same +runtime DLL, or the program does not run at all - a second copy of it in one process is refused. The login path +therefore uses the one in `/usr/bin`, next to the user's own programs, and the user may replace and upgrade it. +What is protected instead is that it is the one the package says it is: pacman checks the files of `msys2-runtime`, +and the cleanup job puts the package back if it was changed - while the server is stopped, before it starts it +again, because the server runs as SYSTEM and would otherwise run code the user of the website wrote. + +`/etc/passwd` (the login shell and home directory) and `/etc/ssh` (the host keys and config) are read-only to the +user as well; everything else in the installation is theirs. + +## The cleanup tasks + +Three scheduled tasks run as SYSTEM, all at startup, and the user cannot stop any of them: + +- `KiK sshd` runs the sshd from `C:\msys2\opt\kik`. It replaces the installation's own `msys2-sshd` service, which + is disabled. +- `KiK restore shell files` runs every 30 minutes and rebuilds the protected copy from its trusted originals, + re-applies the permissions, and puts the home directory, the shell configuration, the website's key and the four + texts back. Its second job is to best-effort revert other mockery and bring a fresh server to the expected state. +- `KiK watch the server` runs every two minutes and starts the server when nothing listens on port 22. The task of + the server only starts it again when it failed, never when it was stopped, so a cleanup job that is killed while + it has the server stopped would otherwise take the site down with it. + +The cleanup job only restarts the server when it has to: when it does not listen at all, when it is older than its +configuration, or when the protected copy or the runtime has to be repaired - those cannot be replaced while the +server holds them open. A working server is left alone, because every start can fail, and failed starts have kept +the site down for hours. The job also never restarts the server while somebody is connected: a session that is open +keeps the port, so a server that is started then could not bind it. + +The server is only down for the short part of the job that needs it down: the protected copy cannot be replaced +while the server holds it open. Everything else - the home directory, the four texts, the permissions of the +installation - is put back while the server runs, because on a slow disk that takes minutes and the site should +have a shell the whole time. + +The task that runs the server ignores a start while it thinks it is still running, so a start that is dropped +leaves the site without a shell. The cleanup job therefore tries three times, killing the processes of the task +in between, before it gives up. + +The deployment does not restart the server. It runs in a session, and that session keeps the port, so a server that +starts during a deployment cannot bind it. The new configuration and the restored programs therefore take effect +at the next run of the cleanup job, which happens within half an hour. + +The server logs to `C:\ProgramData\kik-restore\sshd.log`. The log is appended to, not overwritten, because it is +the only trace of what the server did: a server that is restarted would otherwise take the evidence of an outage +with it. It is rotated when it grows past a hundred megabytes, which takes years. The event logs of windows are +made bigger as well, the security log to a gigabyte: the scanners of the remote desktop alone fill a hundred +megabytes of it in a week. + +A start of the server that fails leaves nothing in that log. So windows records the history of the scheduled tasks +and the start and end of every process, and when the server does not come up, the cleanup job writes the processes +and the state of the server's task to `C:\ProgramData\kik-restore\failed-starts.log`. + +Only keys may log in over SSH. The box stands in the open internet and both of its accounts have a password. + +The files that have to stay belong to the administrators, so the user cannot delete them, and they cannot change the +shell configuration or the key the website logs in with either. The shell reads its configuration from `~/.zsh`, so +the startup files the user could write in the home directory are ignored. + +## Installing the cleanup on the server + +To deploy the cleanup task an the server, run: + + server/scripts/deploy.sh + +The script logs in as `Administrator` - whose shell is a Windows one - copies the scripts and the resources to the +Administrator's home directory and runs the installer there. diff --git a/server/resources/admin/.ssh/authorized_keys b/server/resources/admin/.ssh/authorized_keys new file mode 100644 index 0000000..c6a6df9 --- /dev/null +++ b/server/resources/admin/.ssh/authorized_keys @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIBTHzLm8QMhHIo7kFAvtAFnqpspeR3L3gM8kLoG1137 lennart@erms diff --git a/server/resources/home/.ssh/authorized_keys b/server/resources/home/.ssh/authorized_keys new file mode 100644 index 0000000..9b81cf8 --- /dev/null +++ b/server/resources/home/.ssh/authorized_keys @@ -0,0 +1,2 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDweEH8bhZAHVaAedhTVDb2j/oMEn3vm97xCwCw9LC9 root@nowhere.wirs.ing cygwin-2222 +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIBTHzLm8QMhHIo7kFAvtAFnqpspeR3L3gM8kLoG1137 lennart@erms diff --git a/server/resources/home/.zsh/.zshrc b/server/resources/home/.zsh/.zshrc new file mode 100644 index 0000000..02e6959 --- /dev/null +++ b/server/resources/home/.zsh/.zshrc @@ -0,0 +1,40 @@ +# The protected copies of zsh and cat (and the server itself) live here; keeping them first means the basic +# journey - the prompt and reading the four texts - survives even if the user breaks their own /usr/bin copies. +path=(/opt/kik $path) + +# History shared between sessions. +HISTFILE=~/.zsh_history HISTSIZE=10000 SAVEHIST=10000 +setopt share_history hist_ignore_dups hist_ignore_space interactive_comments auto_cd + +# Completion: menu, case-insensitive, colored. -C skips compaudit, which is slow on +# Windows and meaningless under MSYS2's noacl mounts (rm ~/.zcompdump after adding completions). +autoload -Uz compinit && compinit -C +zstyle ':completion:*' menu select +zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' +zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS} + +# Emacs keys; Up/Down search history for what is already typed. +bindkey -e +autoload -Uz up-line-or-beginning-search down-line-or-beginning-search +zle -N up-line-or-beginning-search && zle -N down-line-or-beginning-search +bindkey '^[[A' up-line-or-beginning-search '^[OA' up-line-or-beginning-search +bindkey '^[[B' down-line-or-beginning-search '^[OB' down-line-or-beginning-search + +# Prompt: user@host:directory, git branch, exit status of the last command if it failed. +# A literal '#' as on Linux: zsh's %# would show '%', since this root is not uid 0. +# The branch is read from .git/HEAD directly: starting git on every prompt is slow on Windows. +precmd() { + local d=$PWD head= + until [[ -e $d/.git || $d == / ]]; do d=${d:h}; done + [[ -f $d/.git/HEAD ]] && read -r head < $d/.git/HEAD + [[ $head == 'ref: '* ]] && git_branch=${head#ref: refs/heads/} || git_branch=${head:0:7} + print -Pn '\e]0;%n@%m: %~\a' +} +setopt prompt_subst +PROMPT='%F{green}%n@%m%f:%F{blue}%~%f${git_branch:+ %5F($git_branch)%f}%(?.. %F{red}[%?]%f)# ' + +alias ls='ls --color=auto' ll='ls -lah' grep='grep --color=auto' + +# Process monitor: htop does not exist for MSYS2 (its /proc only shows MSYS2 processes). +# bottom is a native Windows program; winpty lets it draw in the pty, as Server 2016 has no ConPTY. +alias btm='winpty /ucrt64/bin/btm' diff --git a/server/resources/home/.zshenv b/server/resources/home/.zshenv new file mode 100644 index 0000000..3625bba --- /dev/null +++ b/server/resources/home/.zshenv @@ -0,0 +1,7 @@ +# Preset what MSYS2's /etc/profile would otherwise start a helper process for (~90 ms each here). +# TZ has to match the Windows timezone (W. Europe Standard Time). +export LANG=en_US.UTF-8 TZ=Europe/Berlin + +# The shell reads its configuration from here, not from the home directory: the user may not change it, and the +# files in the home directory that zsh would read otherwise (.zprofile, .zlogin) are ignored. +export ZDOTDIR=~/.zsh diff --git a/server/resources/home/CODE_OF_CONDUCT b/server/resources/home/CODE_OF_CONDUCT new file mode 100644 index 0000000..243da37 --- /dev/null +++ b/server/resources/home/CODE_OF_CONDUCT @@ -0,0 +1,31 @@ + +┌─[38;2;31;154;63m┤ [0m[1mCode of Conduct[0m[38;2;31;154;63m ├[0m────────────────────────────────────────────────────────────┐ +│ Khaos im Kiez ist eine Veranstaltung des Chaos Computer Club Berlin e.V. │ +│ (CCCB). Damit sich alle wohlfühlen, gelten diese Regeln für alle │ +│ Teilnehmenden, Vortragenden und Helfenden. │ +│ │ +│ [38;2;31;154;63m> [0m[1mSei nett zueinander.[0m Geh respektvoll und freundlich miteinander um, auch │ +│ wenn du anderer Meinung bist. │ +│ [38;2;31;154;63m> [0m[1mKeine Diskriminierung.[0m Rassismus, Sexismus, Queerfeindlichkeit, Ableismus │ +│ und andere menschenverachtende Haltungen haben hier keinen Platz. │ +│ [38;2;31;154;63m> [0m[1mKeine Belästigung.[0m Dazu gehören Beleidigungen, Bedrohungen, Stalking, │ +│ unerwünschte körperliche Berührungen und unerwünschte sexuelle │ +│ Aufmerksamkeit. Ein Nein ist ein Nein. │ +│ [38;2;31;154;63m> [0m[1mFrag vor dem Fotografieren.[0m Fotos, Video- und Tonaufnahmen von Personen nur │ +│ mit deren Einverständnis. Das gilt auch für Talks und Workshops. │ +│ [38;2;31;154;63m> [0m[1mAchte auf Geräte und Eigentum.[0m Fass fremde Geräte nicht ohne Erlaubnis an. │ +│ Geh pfleglich mit den Räumen und dem Inventar um. │ +│ [38;2;31;154;63m> [0m[1mSei neugierig, nicht übergriffig.[0m Chaos ja, Grenzenüberschreitungen nein. │ +│ │ +│ [1mHausrecht:[0m Die Orga hat Hausrecht. Bei Verstößen gegen diese Regeln kann sie │ +│ Verwarnungen aussprechen, Personen der Veranstaltung verweisen oder ein │ +│ Hausverbot erteilen. Den Anweisungen der Orga ist Folge zu leisten. │ +│ │ +│ [1mProbleme?[0m Wenn dir etwas passiert oder du etwas beobachtest, sprich eine │ +│ Person aus der Orga an oder schreib an aprl [at] berlin [dot] ccc [dot] de. │ +│ Hinweise werden vertraulich behandelt. │ +└────────────────────────────────────────────────────────────────────────────────┘ + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + ]8;;https://berlin.ccc.de/kik/\[38;2;31;154;63mStartseite[0m]8;;\[38;2;31;154;63m · [0m]8;;https://berlin.ccc.de/page/impressum/\[38;2;31;154;63mImpressum[0m]8;;\ + diff --git a/server/resources/home/CODE_OF_CONDUCT.en b/server/resources/home/CODE_OF_CONDUCT.en new file mode 100644 index 0000000..1639082 --- /dev/null +++ b/server/resources/home/CODE_OF_CONDUCT.en @@ -0,0 +1,30 @@ + +┌─[38;2;31;154;63m┤ [0m[1mCode of Conduct[0m[38;2;31;154;63m ├[0m────────────────────────────────────────────────────────────┐ +│ Khaos im Kiez is an event of the Chaos Computer Club Berlin e.V. (CCCB). To │ +│ make everyone feel comfortable, these rules apply to all attendees, speakers │ +│ and helpers. │ +│ │ +│ [38;2;31;154;63m> [0m[1mBe nice to each other.[0m Treat each other respectfully and kindly, even when │ +│ you disagree. │ +│ [38;2;31;154;63m> [0m[1mNo discrimination.[0m Racism, sexism, queerphobia, ableism and other hateful │ +│ attitudes have no place here. │ +│ [38;2;31;154;63m> [0m[1mNo harassment.[0m This includes insults, threats, stalking, unwanted physical │ +│ contact and unwanted sexual attention. No means no. │ +│ [38;2;31;154;63m> [0m[1mAsk before taking pictures.[0m Photos, video and audio recordings of people │ +│ only with their consent. This also applies to talks and workshops. │ +│ [38;2;31;154;63m> [0m[1mRespect devices and property.[0m Do not touch other people's devices without │ +│ permission. Treat the rooms and furniture with care. │ +│ [38;2;31;154;63m> [0m[1mBe curious, not intrusive.[0m Chaos yes, crossing boundaries no. │ +│ │ +│ [1mHouse rules:[0m The organizers have the right to exclude people from the premises │ +│ (Hausrecht). In case of violations they may issue warnings, ask people to │ +│ leave, or ban them from the event. Follow the organizers' instructions. │ +│ │ +│ [1mProblems?[0m If something happens to you or you notice something, talk to a │ +│ member of the organizing team or write to aprl [at] berlin [dot] ccc [dot] de. │ +│ Reports are treated confidentially. │ +└────────────────────────────────────────────────────────────────────────────────┘ + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + ]8;;https://berlin.ccc.de/kik/en.html\[38;2;31;154;63mHome[0m]8;;\[38;2;31;154;63m · [0m]8;;https://berlin.ccc.de/page/impressum/\[38;2;31;154;63mLegal notice[0m]8;;\ + diff --git a/server/resources/home/README b/server/resources/home/README new file mode 100644 index 0000000..57905aa --- /dev/null +++ b/server/resources/home/README @@ -0,0 +1,79 @@ + +[1mKHAOS IM [0m[1m[38;2;255;42;42mKIEZ[0m +[38;2;31;154;63mCCC Berlin · 28. – 29.11.2026[0m + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m +]8;;https://berlin.ccc.de/kik/#infos\[1] Infos]8;;\ ]8;;https://berlin.ccc.de/kik/#mitmachen\[2] Mitmachen]8;;\ ]8;;https://berlin.ccc.de/kik/#anfahrt\[3] Anfahrt]8;;\ +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + +┌─[38;2;31;154;63m┤ [0m[1m1 Infos[0m[38;2;31;154;63m ├[0m────────────────────────────────────────────────────────────────────┐ +│ Khaos im Kiez ist ein kleines Chaos-Event, back to the roots: inspiriert von │ +│ anderen kleinen Chaos-Events. Ein Wochenende zum Chillen und um die Seite von │ +│ Chaos-Events zu erleben, für die bei größeren Events oft keine Zeit mehr │ +│ bleibt. │ +│ │ +│ Du kannst einen Talk oder Workshop halten, an deinen Projekten schrauben, │ +│ gemeinsam hacken, löten, basteln oder einfach vorbeikommen, zuhören und Leute │ +│ kennenlernen. Alle sind willkommen, die Lust auf $Dinge, Neugier und Chaos │ +│ mitbringen. │ +│ │ +│ [38;2;31;154;63mWas : [0mKhaos im Kiez (KiK) │ +│ [38;2;31;154;63mWann : [0mSa 28.11. – So 29.11.2026, 11:00 – 23:59 │ +│ [38;2;31;154;63mWo : [0mMarienstraße 11, 10117 Berlin │ +│ [38;2;31;154;63mWer : [0mChaos Computer Club Berlin │ +│ [38;2;31;154;63mPreis : [0m0,00 € (Ticket trotzdem nötig, ~50 Plätze) │ +│ [38;2;31;154;63mFahrplan : [0m]8;;https://cfp.berlin.ccc.de\cfp.berlin.ccc.de]8;;\ │ +│ [38;2;31;154;63mEssen : [0mEwiges Frühstück, vegan │ +│ [38;2;31;154;63mBarrierefrei : [0mNicht barrierefrei. │ +│ [38;2;31;154;63mRegeln : [0m]8;;https://berlin.ccc.de/kik/coc.html\Code of Conduct]8;;\ │ +└────────────────────────────────────────────────────────────────────────────────┘ + +┌─[38;2;31;154;63m┤ [0m[1m2 Mitmachen[0m[38;2;31;154;63m ├[0m────────────────────────────────────────────────────────────────┐ +│ [1mTicket:[0m Anmeldung über den Ticketshop. Das Ticket ist kostenlos, aber die │ +│ Plätze sind begrenzt. │ +│ │ +│ ]8;;https://tickets.berlin.ccc.de/cccb/kik-v0.1/\[38;2;255;42;42m[ Ticket sichern ][0m]8;;\ │ +│ │ +│ [1mTalks & Workshops:[0m Reiche deinen Beitrag im Call for Participation ein und │ +│ schau dir später den Fahrplan an. │ +│ │ +│ ]8;;https://cfp.berlin.ccc.de/kik-v01/cfp\[ Talk einreichen ]]8;;\ ]8;;https://cfp.berlin.ccc.de/kik-v01/schedule\[ Fahrplan ]]8;;\ │ +│ │ +│ [1mSonstiges:[0m Du willst anders helfen oder hast Fragen? Schreib an aprl [at] │ +│ berlin [dot] ccc [dot] de. │ +└────────────────────────────────────────────────────────────────────────────────┘ + +┌─[38;2;31;154;63m┤ [0m[1m3 Anfahrt[0m[38;2;31;154;63m ├[0m──────────────────────────────────────────────────────────────────┐ +│ [38;2;31;154;63mAdresse : [0mClubräume im Hinterhof der Marienstraße 11, 10117 Berlin │ +│ [38;2;31;154;63mKoordinaten : [0m52,52194° N, 13,38261° O │ +│ [38;2;31;154;63mFahrrad : [0mIm Innenhof gibt es eine begrenzte Zahl an Fahrradständern. Auf │ +│ dem Weg liegen viele Fahrradstraßen, nutz die am besten, z. B. │ +│ mit ]8;;http://www.bbbike.de/\BBBike.de]8;;\. │ +│ [38;2;31;154;63mÖPNV : [0mDer Club liegt direkt beim S+U-Bahnhof Friedrichstraße (auch │ +│ Regionalbahnen). Vom oberirdischen S-Bahn-Steig (S3/S5/S7) │ +│ nimmst du den Ausgang Schiffbauerdamm und gehst unter der │ +│ Bahnbrücke über die Spree. Über die Albrechtstraße kommst du │ +│ zur Marienstraße. │ +│ [38;2;31;154;63mFernverkehr : [0mAussteigen in Berlin Hauptbahnhof, dann mit S-Bahn oder │ +│ Regionalbahn Richtung Osten eine Station bis Friedrichstraße. │ +│ Bahnhof Richtung Spree verlassen, über die Fußgängerbrücke und │ +│ der Albrechtstraße bis zur Stichstraße Marienstraße folgen. │ +│ [38;2;31;154;63mFlugzeug : [0mBER: Airport Express (RE7, RB14) oder S9 bis Friedrichstraße, │ +│ alternativ FEX bis Hauptbahnhof (dann wie Fernverkehr). │ +│ Achtung: Terminal 5 (früher SXF) ist nicht mit dem Rest des BER │ +│ verbunden, dort fährt nur die S9. Flugplatz Strausberg (EDAY): │ +│ S7 direkt bis Friedrichstraße. │ +│ [38;2;31;154;63mAuto : [0mZufahrt von Hauptbahnhof oder Brandenburger Tor über die │ +│ Luisenstraße. Von der Friedrichstraße entweder über │ +│ Schiffbauerdamm und Albrechtstraße (Außengastronomie und │ +│ Kopfsteinpflaster) oder über Reinhardstraße und Luisenstraße │ +│ (die Albrechtstraße ist nur in Gegenrichtung befahrbar). │ +│ [38;2;31;154;63mParken : [0mAchtung: Es gibt kaum Parkplätze, und die Marienstraße und alle │ +│ umliegenden Straßen sind parkraumbewirtschaftet. │ +│ │ +│ ]8;;https://www.openstreetmap.org/node/3872556357#map=20/52.5217003/13.3828041&layers=H\[ Karte (OpenStreetMap) ]]8;;\ │ +└────────────────────────────────────────────────────────────────────────────────┘ + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + ]8;;https://berlin.ccc.de/page/impressum/\[38;2;31;154;63mImpressum[0m]8;;\[38;2;31;154;63m · [0m]8;;https://berlin.ccc.de/\[38;2;31;154;63mCCC Berlin[0m]8;;\ + diff --git a/server/resources/home/README.en b/server/resources/home/README.en new file mode 100644 index 0000000..5b524e3 --- /dev/null +++ b/server/resources/home/README.en @@ -0,0 +1,77 @@ + +[1mKHAOS IM [0m[1m[38;2;255;42;42mKIEZ[0m +[38;2;31;154;63mCCC Berlin · 2026-11-28 – 2026-11-29[0m + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m +]8;;https://berlin.ccc.de/kik/en.html#infos\[1] Info]8;;\ ]8;;https://berlin.ccc.de/kik/en.html#join\[2] Join in]8;;\ ]8;;https://berlin.ccc.de/kik/en.html#getting-here\[3] Getting here]8;;\ +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + +┌─[38;2;31;154;63m┤ [0m[1m1 Info[0m[38;2;31;154;63m ├[0m─────────────────────────────────────────────────────────────────────┐ +│ Khaos im Kiez is a small chaos event, back to the roots: inspired by other │ +│ small chaos events. A weekend to chill and to experience the side of chaos │ +│ events that often gets no time at larger events. │ +│ │ +│ Give a talk or workshop, work on your projects, hack together, solder, tinker, │ +│ or simply drop by, listen and meet people. Everyone who brings a love of │ +│ $things, curiosity and a bit of chaos is welcome. │ +│ │ +│ [38;2;31;154;63mWhat : [0mKhaos im Kiez (KiK) │ +│ [38;2;31;154;63mWhen : [0mSat 2026-11-28 – Sun 2026-11-29, 11:00 – 23:59 │ +│ [38;2;31;154;63mWhere : [0mMarienstraße 11, 10117 Berlin, Germany │ +│ [38;2;31;154;63mWho : [0mChaos Computer Club Berlin │ +│ [38;2;31;154;63mPrice : [0m€0.00 (ticket still required, ~50 seats) │ +│ [38;2;31;154;63mSchedule : [0m]8;;https://cfp.berlin.ccc.de\cfp.berlin.ccc.de]8;;\ │ +│ [38;2;31;154;63mFood : [0mEternal breakfast, vegan │ +│ [38;2;31;154;63mAccessibility : [0mNot accessible. │ +│ [38;2;31;154;63mRules : [0m]8;;https://berlin.ccc.de/kik/coc-en.html\Code of Conduct]8;;\ │ +└────────────────────────────────────────────────────────────────────────────────┘ + +┌─[38;2;31;154;63m┤ [0m[1m2 Join in[0m[38;2;31;154;63m ├[0m──────────────────────────────────────────────────────────────────┐ +│ [1mTicket:[0m Register via the ticket shop. The ticket is free, but seats are │ +│ limited. │ +│ │ +│ ]8;;https://tickets.berlin.ccc.de/cccb/kik-v0.1/\[38;2;255;42;42m[ Get ticket ][0m]8;;\ │ +│ │ +│ [1mTalks & workshops:[0m Submit your proposal via the call for participation and │ +│ check the schedule later. │ +│ │ +│ ]8;;https://cfp.berlin.ccc.de/kik-v01/cfp\[ Submit a talk ]]8;;\ ]8;;https://cfp.berlin.ccc.de/kik-v01/schedule\[ Schedule ]]8;;\ │ +│ │ +│ [1mOther:[0m Want to help otherwise or have questions? Write to aprl [at] berlin │ +│ [dot] ccc [dot] de. │ +└────────────────────────────────────────────────────────────────────────────────┘ + +┌─[38;2;31;154;63m┤ [0m[1m3 Getting here[0m[38;2;31;154;63m ├[0m─────────────────────────────────────────────────────────────┐ +│ [38;2;31;154;63mAddress : [0mClub rooms in the back yard of Marienstraße 11, 10117 Berlin │ +│ [38;2;31;154;63mCoordinates : [0m52.52194° N, 13.38261° E │ +│ [38;2;31;154;63mBicycle : [0mA limited number of bike racks are in the courtyard. Many │ +│ bicycle streets lead there, preferably use those, e.g. with │ +│ ]8;;http://www.bbbike.de/\BBBike.de]8;;\. │ +│ [38;2;31;154;63mLocal transit : [0mThe club is right next to S+U Friedrichstraße (regional trains │ +│ stop there too). From the elevated S-Bahn platform (S3/S5/S7) │ +│ take the Schiffbauerdamm exit and walk across the Spree │ +│ beneath the railway bridge. Albrechtstraße leads to │ +│ Marienstraße. │ +│ [38;2;31;154;63mLong distance : [0mGet off at Berlin Hauptbahnhof, then take any S-Bahn or │ +│ regional train eastbound one stop to Friedrichstraße. Leave │ +│ the station towards the Spree, cross the footbridge and follow │ +│ Albrechtstraße to the dead-end Marienstraße. │ +│ [38;2;31;154;63mAir : [0mBER: Airport Express (RE7, RB14) or S9 to Friedrichstraße, or │ +│ FEX to Hauptbahnhof (then as above). Note: Terminal 5 │ +│ (formerly SXF) is not connected to the rest of BER, only the │ +│ S9 runs there. Strausberg airfield (EDAY): S7 direct to │ +│ Friedrichstraße. │ +│ [38;2;31;154;63mCar : [0mAccess from Hauptbahnhof or Brandenburger Tor via │ +│ Luisenstraße. From Friedrichstraße either via Schiffbauerdamm │ +│ and Albrechtstraße (outdoor seating and cobblestones) or via │ +│ Reinhardstraße and Luisenstraße (Albrechtstraße is one-way the │ +│ other direction). │ +│ [38;2;31;154;63mParking : [0mWarning: parking is scarce, and Marienstraße and all │ +│ surrounding streets are subject to paid parking zones. │ +│ │ +│ ]8;;https://www.openstreetmap.org/node/3872556357#map=20/52.5217003/13.3828041&layers=H\[ Map (OpenStreetMap) ]]8;;\ │ +└────────────────────────────────────────────────────────────────────────────────┘ + +[38;2;31;154;63m──────────────────────────────────────────────────────────────────────────────────[0m + ]8;;https://berlin.ccc.de/page/impressum/\[38;2;31;154;63mLegal notice[0m]8;;\[38;2;31;154;63m · [0m]8;;https://berlin.ccc.de/\[38;2;31;154;63mCCC Berlin[0m]8;;\ + diff --git a/server/scripts/deploy.sh b/server/scripts/deploy.sh new file mode 100755 index 0000000..09fae47 --- /dev/null +++ b/server/scripts/deploy.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Deploys the cleanup job to the shell server and installs it there. +# +# server/scripts/deploy.sh [-i KEYFILE] [-h HOST] [--uninstall] +# +# The job runs on the box as SYSTEM, never as the root user. The Administrator account sets it up; its shell is a +# Windows one, so the commands we run there are Windows commands. +# +# The Administrator logs in with the personal key of the deployer, from the agent or from -i. The key of the website +# never gets administrator rights: it only logs in as the root user. +set -euo pipefail + +HOST=nowhere.wirs.ing +USER=Administrator +KEYFILE='' +UNINSTALL=0 + +while [ $# -gt 0 ]; do + case $1 in + -i) KEYFILE=$2; shift 2 ;; + -h) HOST=$2; shift 2 ;; + --uninstall) UNINSTALL=1; shift ;; + *) echo "usage: $(basename "$0") [-i KEYFILE] [-h HOST] [--uninstall]" >&2; exit 2 ;; + esac +done + +repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +server="$repo/server" +remote='C:\Users\Administrator\kik' # where the installer is put, in the home of the Administrator +remotePath='/c/Users\Administrator\kik' # the same place, as the file transfer sees it +temporary=() + +# The host key is the one the website pins, so that the deployment cannot be intercepted. +expected=$(sed -n "s/.*const HOST_KEY = '\([^']*\)'.*/\1/p" "$repo/src/scripts/terminal.ts") +known=$(mktemp) +temporary+=("$known") +trap 'rm -f "${temporary[@]}"' EXIT +ssh-keyscan -t ed25519 "$HOST" > "$known" 2>/dev/null +actual=$(ssh-keygen -lf "$known" | awk '{print $2}') +if [ "$actual" != "$expected" ]; then + echo "the host key of $HOST is $actual, but $expected is expected" >&2 + exit 1 +fi + +# The site logs in with the first key in the authorized_keys of the user on the box, so it has to be the right one. +sitekey=$(ssh-keygen -lf "$server/resources/home/.ssh/authorized_keys" | awk 'NR==1 {print $2}') +if [ "$sitekey" != 'SHA256:KUEv4d4+75h41l0OGTWCA2FbtEOQZ047ujkeh+kkFW0' ]; then + echo "the key of the website is not the first one in server/resources/home/.ssh/authorized_keys" >&2 + exit 1 +fi + +options=(-o "UserKnownHostsFile=$known" -o StrictHostKeyChecking=yes) +if [ -n "$KEYFILE" ]; then options+=(-i "$KEYFILE"); fi +ssh=(ssh "${options[@]}" "$USER@$HOST") +scp=(scp "${options[@]}") + +if [ "$UNINSTALL" = 1 ]; then + "${ssh[@]}" "if exist $remote\\scripts\\install_restore_task.ps1 (powershell -NoProfile -ExecutionPolicy Bypass -File $remote\\scripts\\install_restore_task.ps1 -Uninstall) else (echo Nothing is installed.)" + exit +fi + +# The installer looks for the resources next to itself, so both directories go to the server. What was there +# before is removed, so that files that are gone from the repository do not stay on the box. +"${ssh[@]}" "if exist $remote rmdir /s /q $remote" +"${ssh[@]}" "mkdir $remote" +"${scp[@]}" -r "$server/scripts" "$server/resources" "$USER@$HOST:$remotePath/" +"${ssh[@]}" "powershell -NoProfile -ExecutionPolicy Bypass -File $remote\\scripts\\install_restore_task.ps1" diff --git a/server/scripts/install_restore_task.ps1 b/server/scripts/install_restore_task.ps1 new file mode 100644 index 0000000..18230dc --- /dev/null +++ b/server/scripts/install_restore_task.ps1 @@ -0,0 +1,605 @@ +# Sets up the shell server so the website's root user can install packages with pacman, while the basic user +# journey - logging in with the key, the prompt, the home directory and the four text files - cannot be broken. +# +# The whole MSYS2 installation belongs to the root user: they may write everywhere and run pacman. The login path +# the journey depends on - the sshd, the login shell zsh and cat - is kept as a protected copy in C:\msys2\opt\kik +# that only SYSTEM and the administrators may write. The sshd runs as SYSTEM from that copy (the scheduled task +# "KiK sshd"), so replacing /usr/bin/sshd does not touch the running server. A second scheduled task, +# "KiK restore shell files", puts the home directory, the four texts and the protected copy back every 30 minutes. +# +# opt/kik works because its MSYS2 runtime resolves the same installation root (C:\msys2) as /usr/bin, so the login +# shell and the user's own tools share one cygwin runtime. A separate second installation cannot: two runtimes in +# one process tree break each other's file descriptors, and pacman then cannot even lock its database. +# +# Run this in an elevated PowerShell on the server, with this script and the ../resources directory next to it: +# powershell -ExecutionPolicy Bypass -File .\install_restore_task.ps1 +# Remove the tasks and the protected copy again (the installation goes back to a normal cygrunsrv sshd) with: +# powershell -ExecutionPolicy Bypass -File .\install_restore_task.ps1 -Uninstall +[CmdletBinding()] +param( + [string]$HomeDir = 'C:\msys2\home\root', + [switch]$Uninstall +) + +$ErrorActionPreference = 'Stop' +$msys = 'C:\msys2' +$kik = "$msys\opt\kik" +$installDir = 'C:\ProgramData\kik-restore' +$copiesDir = Join-Path $installDir 'files' +$binDir = Join-Path $installDir 'bin' +$sshdBat = Join-Path $installDir 'run-sshd.bat' +$restoreTask = 'KiK restore shell files' +$sshdTask = 'KiK sshd' +$watchTask = 'KiK watch the server' +$service = 'msys2-sshd' + +# The programs the journey needs, kept out of the user's reach. sshd-session and sshd-auth are the per-connection +# helpers OpenSSH 10 re-executes; zsh is the login shell; cat reads the four texts. +$loginBinaries = "$msys\usr\bin\sshd.exe", "$msys\usr\lib\ssh\sshd-session.exe", "$msys\usr\lib\ssh\sshd-auth.exe", + "$msys\usr\bin\zsh.exe", "$msys\usr\bin\cat.exe" + +# The runtime is not among them: a program and the shell that starts it have to use the same runtime, or the +# program does not run at all. The login path therefore uses the one in /usr/bin, and the user may replace it - +# pacman checks that it is the one the package says it is, and the cleanup job puts it back if it is not. +$runtimeFiles = '/usr/bin/msys-2.0.dll' + +# The copies the task restores from and the script it runs both live in $installDir, which only SYSTEM and the +# administrators may read or write. +$restoreScript = @' +# Puts the shell server back into shape and keeps the protected login path in place. Runs as SYSTEM every 30 minutes +# and at startup; the root user can neither stop it nor change the copies it restores from. +param([string]$HomeDir = 'C:\msys2\home\root') +$msys = 'C:\msys2' +$kik = "$msys\opt\kik" +$log = Join-Path $PSScriptRoot 'restore.log' +$copies = Join-Path $PSScriptRoot 'files\home' +$binDir = Join-Path $PSScriptRoot 'bin' + +# The account of the shell server's root user, whose id the files in its home directory belong to. +$passwd = Get-Content "$msys\etc\passwd" -ErrorAction SilentlyContinue | Where-Object { $_ -like 'root:*' } +$sid = if ($passwd) { ($passwd -split ':')[4].Split(',')[-1] } + +$system = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-18') +$admins = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544') + +function Write-Log($message) { + "$(Get-Date -Format s) $message" | Out-File -FilePath $log -Append +} + +# Removes a file, a directory or a link, but never what a link points to. +function Remove-Anything($path) { + $item = Get-Item -LiteralPath $path -Force + if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) { + if ($item.PSIsContainer) { [IO.Directory]::Delete($path) } else { [IO.File]::Delete($path) } + } elseif ($item.PSIsContainer) { + Remove-Item -LiteralPath $path -Recurse -Force + } else { + Remove-Item -LiteralPath $path -Force + } +} + +# A path that only SYSTEM and the administrators own. $userRights is what the root user may do: 'None' (the ssh keys +# and config), 'Read' (the account database) or 'ReadAndExecute' (the login programs it has to run). +function Set-LockedAcl($path, $forDirectory, $userRights) { + $acl = Get-Acl -LiteralPath $path + $acl.SetAccessRuleProtection($true, $false) + foreach ($rule in @($acl.Access)) { [void]$acl.RemoveAccessRuleSpecific($rule) } + $acl.SetOwner($admins) + $inherit = if ($forDirectory) { 'ContainerInherit,ObjectInherit' } else { 'None' } + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($system, 'FullControl', $inherit, 'None', 'Allow'))) + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($admins, 'FullControl', $inherit, 'None', 'Allow'))) + if ($userRights -ne 'None' -and $sid) { + $user = New-Object System.Security.Principal.SecurityIdentifier($sid) + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($user, $userRights, $inherit, 'None', 'Allow'))) + } + Set-Acl -LiteralPath $path -AclObject $acl +} + +# The website logs in with a key in the authorized_keys of the user. The user may keep keys of their own, so only +# the key of the website is put back. +function Restore-Keys($target, $source) { + $required = @(Get-Content -LiteralPath $source | Where-Object { $_.Trim() }) + $blobs = $required | ForEach-Object { ($_ -split '\s+')[1] } + $keys = @() + if (Test-Path -LiteralPath $target) { + $keys = @(Get-Content -LiteralPath $target | Where-Object { $_.Trim() -and $blobs -notcontains ($_ -split '\s+')[1] }) + } + [IO.File]::WriteAllText($target, (($keys + $required) -join "`n") + "`n") +} + +# The shell configuration and the key the website logs in with must not change, the four texts may be edited. +$readOnly = '.zshrc', '.zshenv', 'authorized_keys' + +# The permissions of the home directory and of the files in it that have to stay: the user may read them and write +# the ones that may change, and delete their own files, but not the home directory itself and not the files the +# website needs. Only SYSTEM and the administrators own them, so the user cannot take the permissions away again. +function Set-HomeAcl($path, $forDirectory, $writable) { + if (-not $sid) { return } + try { + $user = New-Object System.Security.Principal.SecurityIdentifier($sid) + $acl = Get-Acl -LiteralPath $path + $acl.SetAccessRuleProtection($true, $false) + foreach ($rule in @($acl.Access)) { [void]$acl.RemoveAccessRuleSpecific($rule) } + $acl.SetOwner($admins) + $none = [System.Security.AccessControl.InheritanceFlags]::None + $children = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit + $inheritOnly = [System.Security.AccessControl.PropagationFlags]::InheritOnly + $full = [System.Security.AccessControl.FileSystemRights]::FullControl + $some = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute -bor [System.Security.AccessControl.FileSystemRights]::Write + $read = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute + $inherit = if ($forDirectory) { $children } else { $none } + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList $system, $full, $inherit, 'None', 'Allow')) + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList $admins, $full, $inherit, 'None', 'Allow')) + $userRights = if ($writable) { $some } else { $read } + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList $user, $userRights, $none, 'None', 'Allow')) + if ($forDirectory) { + # the files in it are the user's own, they may delete them + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList $user, $full, $children, $inheritOnly, 'Allow')) + } + Set-Acl -LiteralPath $path -AclObject $acl + } catch { + Write-Log "the permissions of $path are not set: $_" + } +} + +# The home directory is the one from /etc/passwd, which the user cannot change, but which they can delete. A new one +# gets MSYS2's default files from /etc/skel, which MSYS2 itself only copies into a home that does not exist yet. +function New-Home($path) { + New-Item -ItemType Directory -Path $path | Out-Null + Set-HomeAcl $path $true $true + Get-ChildItem -LiteralPath "$msys\etc\skel" -Force | Copy-Item -Destination $path -Recurse -Force +} + +# The server is only stopped when it has to be: when it does not run, when it is older than its configuration, or +# when it holds open what has to be repaired - its programs in opt/kik or the runtime. A working server is left alone, +# because every start can fail, and a failed start has kept the site down for hours. +# +# Stopping the task does not take the server with it, so its processes are killed by hand and the task is waited +# for: it ignores a new instance while one is running, so a start would be dropped. +function Stop-Sshd { + Stop-ScheduledTask -TaskName 'KiK sshd' -ErrorAction SilentlyContinue + Get-CimInstance Win32_Process -Filter "Name='cmd.exe'" | Where-Object { $_.CommandLine -match 'cmd\.exe\s+/c\s+"?C:\\ProgramData\\kik-restore\\run-sshd\.bat' } | + ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } + Get-Process -Name sshd -ErrorAction SilentlyContinue | Stop-Process -Force + # the server leaves the processes of the sessions it has served behind, and they hold the runtime and the + # protected programs open, so those cannot be replaced while they are there + Get-Process -Name 'sshd-session' -ErrorAction SilentlyContinue | Stop-Process -Force + $waited = 0 + while ((Get-ScheduledTask -TaskName 'KiK sshd').State -ne 'Ready' -and $waited -lt 30) { Start-Sleep 1; $waited++ } + $waited = 0 + while ((Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) -and $waited -lt 30) { Start-Sleep 1; $waited++ } +} + +# What the box looks like when the server did not come up. Nothing else records a failed start, and the reboot that +# ends the outage takes the evidence with it. +function Save-Snapshot($attempt) { + $task = Get-ScheduledTask -TaskName 'KiK sshd' + $info = $task | Get-ScheduledTaskInfo + $lines = @("== $(Get-Date -Format s) attempt ${attempt}: the task is $($task.State), last run $($info.LastRunTime), result 0x$('{0:X}' -f $info.LastTaskResult)") + $lines += Get-NetTCPConnection -LocalPort 22 -ErrorAction SilentlyContinue | ForEach-Object { "port 22: $($_.LocalAddress) $($_.State) pid $($_.OwningProcess)" } + $lines += Get-CimInstance Win32_Process | Sort-Object CreationDate | ForEach-Object { + '{0:MM-dd HH:mm:ss} {1} pid {2} parent {3} session {4}: {5}' -f $_.CreationDate, $_.Name, $_.ProcessId, $_.ParentProcessId, $_.SessionId, $_.CommandLine + } + $lines | Out-File -FilePath (Join-Path $PSScriptRoot 'failed-starts.log') -Append +} + +# The server is started again and waited for: a deployment or a crash must never leave the site without a shell. +# The task ignores a new instance while it thinks one is running, so when the port stays closed its processes are +# killed and it is started again. +function Start-Sshd { + for ($attempt = 1; $attempt -le 3; $attempt++) { + Start-ScheduledTask -TaskName 'KiK sshd' + $waited = 0 + while (-not (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) -and $waited -lt 30) { Start-Sleep 1; $waited++ } + if (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) { return $true } + Write-Log "the server did not come up (attempt $attempt)" + Save-Snapshot $attempt + Stop-Sshd + } + return $false +} + +# Runs a program and gives up after a while: pacman can wait for the lock of its database, and the server must not +# stay down because of it. The exit code is returned, or -1 when it did not finish in time. +function Invoke-Bounded($program, $arguments, $seconds) { + $process = Start-Process -FilePath $program -ArgumentList $arguments -NoNewWindow -PassThru ` + -RedirectStandardOutput (Join-Path $env:TEMP 'kik-pacman.out') -RedirectStandardError (Join-Path $env:TEMP 'kik-pacman.err') + # the handle is taken while the process runs, otherwise its exit code is not available afterwards + $null = $process.Handle + if (-not $process.WaitForExit($seconds * 1000)) { + Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue + return -1 + } + return $process.ExitCode +} + +$netError = $null +$connections = @(Get-NetTCPConnection -LocalPort 22 -ErrorAction SilentlyContinue -ErrorVariable netError) +# An open session keeps the port, so the server is only stopped when there is none. A query that fails is not a +# reason to disturb a session. The processes of the sessions are left behind by the server when a client goes away, +# so they say nothing about whether anybody is connected. +$busy = @($connections | Where-Object { $_.State -eq 'Established' }).Count -gt 0 +$mayStop = -not $netError -and -not $busy +# The runtime of the installation belongs to the user's programs and is not protected: a program and the shell that +# starts it have to use the same one, or the program does not run at all. What has to be protected is that it is the +# one the package says it is, because the server runs as SYSTEM. The check takes a while, so it runs while the +# server is up - the server must not wait for it. +$runtimeBroken = $false +if ($mayStop) { + $runtimeBroken = (Invoke-Bounded "$msys\usr\bin\pacman.exe" @('-Qkk', 'msys2-runtime') 120) -ne 0 +} + +# The home directory and the four texts: the server does not hold them open, so they are put back while it runs. +# On a slow disk this takes minutes, and the site has a shell the whole time. +if (-not (Test-Path -LiteralPath $HomeDir)) { + New-Home $HomeDir + Write-Log "created $HomeDir" +} elseif ((Get-Item -LiteralPath $HomeDir -Force).Attributes -band [IO.FileAttributes]::ReparsePoint) { + Remove-Anything $HomeDir + New-Home $HomeDir + Write-Log "replaced the link $HomeDir" +} else { + Set-HomeAcl $HomeDir $true $true +} + +foreach ($copy in Get-ChildItem -LiteralPath $copies -Recurse -File -Force) { + $target = Join-Path $HomeDir $copy.FullName.Substring($copies.Length).TrimStart('\') + try { + $dir = Split-Path -Parent $target + if ((Test-Path -LiteralPath $dir) -and -not (Get-Item -LiteralPath $dir -Force).PSIsContainer) { + Remove-Anything $dir + } + if (-not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } + Set-HomeAcl $dir $true $true + if (Test-Path -LiteralPath $target) { + $item = Get-Item -LiteralPath $target -Force + if ($item.PSIsContainer -or $item.Attributes -band [IO.FileAttributes]::ReparsePoint) { + # anything but a file is replaced, so that the files are always the text files they should be + Remove-Anything $target + } else { + # the user may have locked the file; taking it back lets us write it + takeown /f $target /a | Out-Null + } + } + if ($copy.Name -eq 'authorized_keys') { + Restore-Keys $target $copy.FullName + } else { + Copy-Item -LiteralPath $copy.FullName -Destination $target -Force + } + Set-HomeAcl $target $false ($readOnly -notcontains $copy.Name) + # the user may have made the file read-only for themselves, the four texts are theirs to change + (Get-Item -LiteralPath $target -Force).IsReadOnly = $false + Write-Log "restored $($copy.Name)" + } catch { + Write-Log "failed $($copy.Name) : $_" + } +} + +# The whole installation belongs to the user, so pacman can write it. The home directory keeps its own protected +# permissions because they are set without inheritance. +if ($sid) { icacls $msys /grant "*${sid}:(OI)(CI)F" | Out-Null } + +# The protected login path: the copy the sshd and the login shell run from. The user cannot write it, so even after +# they replace or remove their own copies in /usr/bin the server and the journey keep working. The trusted originals +# are in bin\; anything missing from opt/kik or different from its original is put back. Replacing them is the only +# work that needs the server to be stopped, because a running server holds its programs open. +$stale = @(if (Test-Path -LiteralPath $binDir) { + Get-ChildItem -LiteralPath $binDir -File -Force | Where-Object { + $target = Join-Path $kik $_.Name + $_.Name -ne 'msys-2.0.dll' -and (-not (Test-Path -LiteralPath $target) -or (Get-Item -LiteralPath $target -Force).Length -ne $_.Length) + } +}) +# A deployment writes the configuration but cannot restart the server, so a server that is older than its +# configuration is restarted here. +$listener = Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 +$outdated = $listener -and @(Get-Item -LiteralPath "$msys\etc\ssh\sshd_config", (Join-Path $PSScriptRoot 'run-sshd.bat') | + Where-Object { $_.LastWriteTime -gt (Get-Process -Id $listener.OwningProcess).StartTime }).Count -gt 0 +$restart = $mayStop -and (-not $listener -or $outdated -or $runtimeBroken -or $stale.Count -gt 0) + +if ($restart) { + Stop-Sshd + Remove-Item "$kik\msys-2.0.dll" -Force -ErrorAction SilentlyContinue + if ($runtimeBroken) { + # the package is put back while the server is stopped: the file cannot be replaced while it is mapped. + # The pattern is quoted, or the runtime expands it to the files of the working directory. + Invoke-Bounded "$msys\usr\bin\pacman.exe" @('-S', '--noconfirm', '--overwrite', "'*'", 'msys2-runtime') 300 | Out-Null + Write-Log 'restored the runtime of the installation' + } + if (-not (Test-Path -LiteralPath $kik)) { New-Item -ItemType Directory -Path $kik | Out-Null } + foreach ($file in $stale) { + try { + Copy-Item -LiteralPath $file.FullName -Destination (Join-Path $kik $file.Name) -Force + Write-Log "restored opt/kik/$($file.Name)" + } catch { + # a process the server left behind may still hold it open; it is replaced in one of the next runs + Write-Log "failed opt/kik/$($file.Name) : $_" + } + } +} + +# The permissions do not need the server to be stopped, so they are put back on every run. +try { + if (Test-Path -LiteralPath $binDir) { + New-Item -ItemType Directory -Force -Path "$kik\dev\shm", "$kik\dev\mqueue" | Out-Null + Set-LockedAcl $kik $true 'ReadAndExecute' + # /dev is scratch: the user may write it so POSIX shared memory works, the rest of opt/kik stays read-only + if ($sid) { icacls "$kik\dev" /grant "*${sid}:(OI)(CI)M" | Out-Null } + } + + # The account database and the ssh keys and config the SYSTEM server reads: the user may read passwd (programs + # map ids through it) but change none of it, and has no business in /etc/ssh at all. + $rootShell = '/opt/kik/zsh.exe' + $pw = "$msys\etc\passwd" + $lines = Get-Content $pw + if ($lines | Where-Object { $_ -match '^root:' -and $_ -notmatch ':/opt/kik/zsh\.exe$' }) { + ($lines | ForEach-Object { if ($_ -match '^root:') { $_ -replace ':[^:]*$', ":$rootShell" } else { $_ } }) | Set-Content $pw -Encoding ascii + Write-Log 'set the root login shell to the protected zsh' + } + Set-LockedAcl $pw $false 'Read' + if (Test-Path "$msys\etc\ssh") { Set-LockedAcl "$msys\etc\ssh" $true 'None' } +} catch { + Write-Log "the protected login path is not fully in place: $_" +} + +if ($restart) { + if (Start-Sshd) { Write-Log 'restarted the sshd' } else { Write-Log 'the sshd does not listen on port 22' } +} +'@ + +# The server is watched, because the cleanup job may be killed while it has the server stopped: the task of the +# server only starts it again when it failed, never when it was stopped. The watcher is the only thing that brings +# the site back when that happens. +$watchScript = @' +# Starts the server when it is not running. The cleanup job stops it while it puts the protected files back, and it +# can be killed while the server is down - the task of the server does not start it again then. +$log = Join-Path $PSScriptRoot 'watch.log' +if (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) { return } +if ((Get-ScheduledTask -TaskName 'KiK restore shell files').State -eq 'Running') { + # the cleanup job starts the server itself when it is done, but it must not hold it down for ever + $running = (Get-Date) - (Get-ScheduledTaskInfo -TaskName 'KiK restore shell files').LastRunTime + if ($running.TotalMinutes -lt 3) { return } +} +if ((Get-ScheduledTask -TaskName 'KiK sshd').State -eq 'Running') { + # the task is running but nothing listens, so it is stuck and has to be started anew + Stop-ScheduledTask -TaskName 'KiK sshd' + Start-Sleep 5 +} +Start-ScheduledTask -TaskName 'KiK sshd' +"$(Get-Date -Format s) the server was not running and was started" | Out-File -FilePath $log -Append +'@ + +if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { + throw 'Run this in an elevated PowerShell.' +} + +$system = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-18') +$admins = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544') + +$passwd = Get-Content "$msys\etc\passwd" -ErrorAction SilentlyContinue | Where-Object { $_ -like 'root:*' } +if (-not $passwd) { throw "No root user in $msys\etc\passwd." } +$sid = ($passwd -split ':')[4].Split(',')[-1] + +# A previous install may have locked opt/kik, the account database and the ssh keys. The administrators keep +# full control over them, so reset the permissions to inherited now and let this run write freely; the restore +# task locks everything again at the end. +$prevEA = $ErrorActionPreference; $ErrorActionPreference = 'SilentlyContinue' +foreach ($p in "$msys\opt\kik", "$msys\etc\ssh", "$msys\etc\passwd") { + if (Test-Path -LiteralPath $p) { icacls $p /reset /t /q | Out-Null } +} +Get-ChildItem "$msys\etc\ssh", "$msys\etc\passwd" -Force | ForEach-Object { try { $_.IsReadOnly = $false } catch {} } +$ErrorActionPreference = $prevEA + +function Set-LockedAcl($path, $forDirectory, $userRights) { + $acl = Get-Acl -LiteralPath $path + $acl.SetAccessRuleProtection($true, $false) + foreach ($rule in @($acl.Access)) { [void]$acl.RemoveAccessRuleSpecific($rule) } + $acl.SetOwner($admins) + $inherit = if ($forDirectory) { 'ContainerInherit,ObjectInherit' } else { 'None' } + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($system, 'FullControl', $inherit, 'None', 'Allow'))) + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($admins, 'FullControl', $inherit, 'None', 'Allow'))) + if ($userRights -ne 'None') { + $user = New-Object System.Security.Principal.SecurityIdentifier($sid) + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($user, $userRights, $inherit, 'None', 'Allow'))) + } + Set-Acl -LiteralPath $path -AclObject $acl +} + +# The DLLs an MSYS2 program loads, as Windows paths under C:\msys2. +function Get-Libraries($program) { + $paths = @() + $posix = ($program -replace '^C:\\msys2', '') -replace '\\', '/' + foreach ($line in & "$msys\usr\bin\ldd.exe" $posix 2>$null) { + foreach ($m in [regex]::Matches($line, '/usr/[^\s]+\.dll')) { $paths += $m.Value } + } + $paths | Select-Object -Unique | Where-Object { $_ -notin $runtimeFiles } | ForEach-Object { $msys + ($_ -replace '/', '\') } +} + +if ($Uninstall) { + foreach ($t in $restoreTask, $sshdTask, $watchTask) { Unregister-ScheduledTask -TaskName $t -Confirm:$false -ErrorAction SilentlyContinue } + if (Test-Path -LiteralPath $installDir) { Remove-Item -LiteralPath $installDir -Recurse -Force } + if (Test-Path -LiteralPath $kik) { + icacls $kik /reset /t /q 2>$null | Out-Null + Remove-Item -LiteralPath $kik -Recurse -Force -ErrorAction SilentlyContinue + } + # the installation's own cygrunsrv sshd takes over again + $pw = "$msys\etc\passwd" + (Get-Content $pw | ForEach-Object { if ($_ -match '^root:') { $_ -replace ':[^:]*$', ':/usr/bin/zsh' } else { $_ } }) | Set-Content $pw -Encoding ascii + icacls $pw /reset | Out-Null + if (Test-Path "$msys\etc\ssh") { icacls "$msys\etc\ssh" /reset /t /q 2>$null | Out-Null } + Set-Service $service -StartupType Automatic -ErrorAction SilentlyContinue + Start-Service $service -ErrorAction SilentlyContinue + Write-Host "Removed the tasks and $installDir; the $service service serves ssh again." + return +} + +$resources = Join-Path $PSScriptRoot '..\resources' +if (-not (Get-ChildItem -LiteralPath $resources -Recurse -File -Force)) { throw "No files in $resources." } + +$prepared = Get-Item -LiteralPath $installDir -Force -ErrorAction SilentlyContinue +if ($prepared -and $prepared.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw "$installDir is a link, refusing to install." } + +New-Item -ItemType Directory -Force -Path $copiesDir, $binDir | Out-Null + +# Only SYSTEM and the administrators may read or write the copies, the trusted login programs and the scripts. +$acl = New-Object System.Security.AccessControl.DirectorySecurity +$acl.SetAccessRuleProtection($true, $false) +foreach ($owner in $system, $admins) { + $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($owner, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow'))) +} +$acl.SetOwner($admins) +Set-Acl -LiteralPath $installDir -AclObject $acl + +foreach ($item in Get-ChildItem -LiteralPath $installDir -Recurse -Force) { + if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw "$($item.FullName) is a link, refusing to install." } +} +Remove-Item -LiteralPath $copiesDir -Recurse -Force +New-Item -ItemType Directory -Force -Path $copiesDir | Out-Null +Copy-Item -Path (Join-Path $resources '*') -Destination $copiesDir -Recurse -Force + +# The Administrator logs in with the key of the people who deploy, which is in the resources. The keys that are +# already there stay. +$adminKeys = 'C:\Users\Administrator\.ssh\authorized_keys' +$required = @(Get-Content -LiteralPath (Join-Path $resources 'admin\.ssh\authorized_keys') | Where-Object { $_.Trim() }) +$keys = @() +if (Test-Path -LiteralPath $adminKeys) { $keys = @(Get-Content -LiteralPath $adminKeys | Where-Object { $_.Trim() }) } +if (-not ($keys | Where-Object { ($_ -split '\s+')[1] -eq ($required[0] -split '\s+')[1] })) { + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $adminKeys) | Out-Null + [IO.File]::WriteAllText($adminKeys, (($keys + $required) -join "`n") + "`n") +} +[IO.File]::WriteAllText((Join-Path $installDir 'restore.ps1'), $restoreScript) +[IO.File]::WriteAllText((Join-Path $installDir 'watch.ps1'), $watchScript) + +# The trusted login programs: the sshd, its helpers, the login shell and cat, with every DLL they load. The restore +# task puts these into opt/kik, which the user cannot write. +Remove-Item "$binDir\*" -Force -ErrorAction SilentlyContinue +$files = @{} +foreach ($b in $loginBinaries) { + if (-not (Test-Path -LiteralPath $b)) { throw "$b does not exist." } + $files[$b] = $true + foreach ($lib in Get-Libraries $b) { $files[$lib] = $true } +} +foreach ($f in $files.Keys) { Copy-Item -LiteralPath $f -Destination $binDir -Force } + +# Remote Desktop is the way in for the administrator, and the port is open to the internet. It needs network level +# authentication, so that a scanner cannot get a session before it has proven that it knows the password. +$rdpTcp = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' +$nla = (Get-ItemProperty -Path $rdpTcp -Name UserAuthentication).UserAuthentication +Set-ItemProperty -Path $rdpTcp -Name UserAuthentication -Value 1 -Type DWord +if ($nla -ne 1) { + # the setting only counts when the service starts again, which drops the sessions that are open + Restart-Service TermService -Force +} + +# Only the administrator may log in over Remote Desktop. The user of the website is in no group that may log in +# over it, and it must never be an administrator - that is taken away if it somehow got there. +$rootAccount = Get-LocalUser -Name 'root' -ErrorAction SilentlyContinue +if ($rootAccount) { + foreach ($group in 'Administrators', 'Remote Desktop Users') { + $member = Get-LocalGroupMember $group -ErrorAction SilentlyContinue | Where-Object { $_.SID -eq $rootAccount.SID } + if ($member) { + Remove-LocalGroupMember $group $member -Confirm:$false + Write-Host "The root user was in '$group' and has been removed from it." + } + } +} + +# The sshd reads its configuration and finds its helpers in opt/kik; nothing here depends on the user's /usr. +$sshdConfig = "$msys\etc\ssh\sshd_config" +Set-Content -LiteralPath $sshdConfig -Encoding ascii -Value @( + '# The website logs in as root, the deployers as Administrator. Both come in over the websocket bridge.', + 'Port 22', + 'AllowUsers root Administrator', + '# Only keys may log in: the box is in the open internet and the accounts have passwords.', + 'PasswordAuthentication no', + 'KbdInteractiveAuthentication no', + '# Files are protected by Windows ACLs; under MSYS2''s noacl mounts the POSIX modes sshd checks are fake.', + 'StrictModes no', + 'Subsystem sftp internal-sftp', + '# The server and its per-connection helpers are the protected copies, not the ones the user can replace.', + 'SshdSessionPath /opt/kik/sshd-session.exe', + 'SshdAuthPath /opt/kik/sshd-auth.exe' +) + +# The sshd runs as SYSTEM from the protected copy, with opt/kik first on the path so its own DLLs and the session's +# programs (zsh, cat) are the protected ones. The log stays in the install directory, out of the user's reach. +# The log is appended to, not overwritten: it is the only trace of what the server did, and a server that is +# restarted would otherwise take the evidence of the outage with it. It is rotated at a hundred megabytes, which +# takes years to reach. +Set-Content -LiteralPath $sshdBat -Encoding ascii -Value @( + '@echo off', + 'set PATH=C:\msys2\opt\kik;C:\msys2\usr\bin;%PATH%', + 'rem Keep the previous log if it grew too big; the current one is appended to.', + 'if exist C:\ProgramData\kik-restore\sshd.log for %%f in (C:\ProgramData\kik-restore\sshd.log) do if %%~zf GEQ 104857600 move /y C:\ProgramData\kik-restore\sshd.log C:\ProgramData\kik-restore\sshd.log.1', + 'C:\msys2\opt\kik\sshd.exe -D -e >> C:\ProgramData\kik-restore\sshd.log 2>&1' +) + +# The event logs of windows are made bigger as well: they are the only record of what the box itself did. The +# security log gets the most, because the scanners of the remote desktop alone fill a hundred megabytes in a week. +foreach ($eventLog in 'System', 'Application') { + wevtutil sl $eventLog /ms:104857600 | Out-Null +} +wevtutil sl Security /ms:1073741824 | Out-Null + +# A start of the server that fails leaves no trace in its own log, so windows records what the task of the server +# launched and how each process ended: the history of the scheduled tasks, and the start and end of every process. +wevtutil sl Microsoft-Windows-TaskScheduler/Operational /e:true /ms:104857600 | Out-Null +auditpol /set '/subcategory:{0CCE922B-69AE-11D9-BED3-505054503030},{0CCE922C-69AE-11D9-BED3-505054503030}' /success:enable | Out-Null + +# The installation's own cygrunsrv sshd service would fight for port 22; the scheduled task owns the sshd instead. +Set-Service $service -StartupType Disabled -ErrorAction SilentlyContinue +Stop-Service $service -Force -ErrorAction SilentlyContinue + +$atSystem = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest + +$sshdAction = New-ScheduledTaskAction -Execute $sshdBat +$sshdSettings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Seconds 0) -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries +Register-ScheduledTask -TaskName $sshdTask -Action $sshdAction -Trigger (New-ScheduledTaskTrigger -AtStartup) -Principal $atSystem -Settings $sshdSettings -Force | Out-Null + +$restoreAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$installDir\restore.ps1`" -HomeDir `"$HomeDir`"" +$restoreTriggers = @( + New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 30) -RepetitionDuration (New-TimeSpan -Days 3650) + New-ScheduledTaskTrigger -AtStartup +) +$restoreSettings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Minutes 30) -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 5) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries +Register-ScheduledTask -TaskName $restoreTask -Action $restoreAction -Trigger $restoreTriggers -Principal $atSystem -Settings $restoreSettings -Force | Out-Null + +# The watcher looks after the server every two minutes, so that a cleanup job that is killed while it has the server +# stopped does not take the site down with it. +$watchAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$installDir\watch.ps1`"" +$watchTriggers = @( + New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 2) -RepetitionDuration (New-TimeSpan -Days 3650) + New-ScheduledTaskTrigger -AtStartup +) +$watchSettings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Minutes 1) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries +Register-ScheduledTask -TaskName $watchTask -Action $watchAction -Trigger $watchTriggers -Principal $atSystem -Settings $watchSettings -Force | Out-Null + +# The server is started and waited for: it must listen on port 22, or the site has no shell. +function Start-Sshd { + Start-ScheduledTask -TaskName $sshdTask + $waited = 0 + while (-not (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) -and $waited -lt 30) { Start-Sleep 1; $waited++ } + return [bool](Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue) +} + +# The restore task builds opt/kik and sets every permission; run it before starting the sshd that depends on it. +Start-ScheduledTask -TaskName $restoreTask +Start-Sleep -Seconds 6 +$waited = 0 +while ((Get-ScheduledTask -TaskName $restoreTask).State -eq 'Running' -and $waited -lt 60) { Start-Sleep 2; $waited += 2 } + +# The server is not restarted here. It cannot be: the deployment runs in a session, and the port is still in use by +# that session, so a server that starts now cannot bind it. The cleanup job restarts the server when nobody is +# connected, and the new configuration and the restored programs take effect then. A server that is not running at +# all is started here, because then there is no session that could hold the port. +if (-not (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue)) { + if (-not (Start-Sshd)) { + throw "The sshd does not listen on port 22; the task '$sshdTask' says: $((Get-ScheduledTask -TaskName $sshdTask).State), $((Get-ScheduledTaskInfo -TaskName $sshdTask).LastTaskResult)" + } +} +if (-not (Get-NetTCPConnection -LocalPort 22 -State Listen -ErrorAction SilentlyContinue)) { + throw "The sshd does not listen on port 22." +} + +Write-Host "The sshd runs as SYSTEM from C:\msys2\opt\kik (task '$sshdTask'); '$restoreTask' keeps it and the home directory in shape." +Get-Content (Join-Path $installDir 'restore.log') -Tail 10 -ErrorAction SilentlyContinue +Get-CimInstance Win32_Process -Filter "Name='sshd.exe'" | ForEach-Object { $_.CommandLine } diff --git a/server/scripts/make_files.py b/server/scripts/make_files.py new file mode 100644 index 0000000..f716d7f --- /dev/null +++ b/server/scripts/make_files.py @@ -0,0 +1,337 @@ +# Builds the text files for the home directory of the shell server's root user in ../resources/home: README, +# README.en, CODE_OF_CONDUCT and CODE_OF_CONDUCT.en as the website's pages in terminal text with escape sequences. +# The other files there are edited by hand. +# Usage: python3 server/scripts/make_files.py +import pathlib +import textwrap + +ESC = '\x1b' +RESET = f'{ESC}[0m' +BOLD = f'{ESC}[1m' +DIM = f'{ESC}[38;2;31;154;63m' # the page's --dim +HOT = f'{ESC}[38;2;255;42;42m' # the page's --hot +WIDTH = 82 # the web terminal's width, as wide as the page column +INNER = WIDTH - 4 # text width inside "│ " ... " │" +SITE = 'https://berlin.ccc.de/kik/' +IMPRESSUM = 'https://berlin.ccc.de/page/impressum/' +TICKETS = 'https://tickets.berlin.ccc.de/cccb/kik-v0.1/' +CFP = 'https://cfp.berlin.ccc.de/kik-v01/cfp' +SCHEDULE = 'https://cfp.berlin.ccc.de/kik-v01/schedule' +MAP = 'https://www.openstreetmap.org/node/3872556357#map=20/52.5217003/13.3828041&layers=H' + + +def link(url, text, style=''): + return f'{ESC}]8;;{url}{ESC}\\{style}{text}{RESET if style else ""}{ESC}]8;;{ESC}\\' + + +class Line: + """A line of text with its visible width, so boxes can be padded around styled text.""" + def __init__(self, text='', width=None): + self.text, self.width = text, len(text) if width is None else width + + def __add__(self, other): + return Line(self.text + other.text, self.width + other.width) + + +def styled(text, style): + return Line(f'{style}{text}{RESET}', len(text)) + + +def linked(url, text, style=''): + return Line(link(url, text, style), len(text)) + + +def joined(parts, gap=' '): + line = parts[0] + for part in parts[1:]: + line = line + Line(gap) + part + return line + + +def wrap(text, width, links=()): + """Wraps plain text, then turns the given (text, url) pairs into links where they appear.""" + lines = [] + for raw in textwrap.wrap(text, width, break_on_hyphens=False, break_long_words=False): + rendered = raw + for needle, url in links: + rendered = rendered.replace(needle, link(url, needle)) + lines.append(Line(rendered, len(raw))) + return lines + + +def paragraph(text, links=(), lead=None): + """A paragraph, optionally starting with a bold lead-in like "Ticket:".""" + full = f'{lead} {text}' if lead else text + lines = wrap(full, INNER, links) + if lead: + first = lines[0] + lines[0] = Line(first.text.replace(lead, f'{BOLD}{lead}{RESET}', 1), first.width) + return lines + + +def pairs(items, label, links=()): + """A key-value list like the page's: dim "Label :" column, values wrapped with a hanging indent.""" + lines = [] + for key, value in items: + wrapped = wrap(value, INNER - label, links) + lines.append(styled(f'{key} :'.ljust(label), DIM) + wrapped[0]) + lines += [Line(' ' * label) + rest for rest in wrapped[1:]] + return lines + + +def bullets(items): + """A list like the page's: dim "> " marker, bold title, text wrapped with a hanging indent.""" + lines = [] + for title, text in items: + wrapped = wrap(f'{title} {text}', INNER - 2) + first = wrapped[0] + lines.append(styled('> ', DIM) + Line(first.text.replace(title, f'{BOLD}{title}{RESET}', 1), first.width)) + lines += [Line(' ') + rest for rest in wrapped[1:]] + return lines + + +def box(title, lines): + rule = WIDTH - 2 - len(f'─┤ {title} ├') + out = [Line('┌─') + styled('┤ ', DIM) + styled(title, BOLD) + styled(' ├', DIM) + Line('─' * rule + '┐')] + out += [Line('│ ') + line + Line(' ' * (INNER - line.width) + ' │') for line in lines] + out.append(Line('└' + '─' * (WIDTH - 2) + '┘')) + return out + + +def centered(line): + return Line(' ' * ((WIDTH - line.width) // 2)) + line + + +def nav(line): + return [styled('─' * WIDTH, DIM), line, styled('─' * WIDTH, DIM)] + + +def footer(parts): + line = linked(parts[0][1], parts[0][0], DIM) + for text, url in parts[1:]: + line = line + styled(' · ', DIM) + linked(url, text, DIM) + return [styled('─' * WIDTH, DIM), centered(line)] + + +def page(lines): + lines = [Line(), *lines, Line()] + for line in lines: + assert line.width <= WIDTH + 2, (line.width, line.text) + return ''.join(f'{line.text}\n' for line in lines) + + +def readme(t): + label = 3 + max(len(key) for key, _ in t['infos'] + t['route']) + return page([ + styled('KHAOS IM ', BOLD) + styled('KIEZ', BOLD + HOT), + styled(t['date'], DIM), + Line(), + *nav(joined([linked(f'{SITE}{t["page"]}#{anchor}', f'[{n}] {title}') for n, title, anchor in t['sections']])), + Line(), + *box('{} {}'.format(*t['sections'][0][:2]), [ + *paragraph(t['intro'][0]), + Line(), + *paragraph(t['intro'][1]), + Line(), + *pairs(t['infos'], label, links=[('cfp.berlin.ccc.de', 'https://cfp.berlin.ccc.de'), ('Code of Conduct', f'{SITE}{t["coc"]}')]), + ]), + Line(), + *box('{} {}'.format(*t['sections'][1][:2]), [ + *paragraph(t['ticket'], lead=t['ticket_lead']), + Line(), + linked(TICKETS, f'[ {t["get_ticket"]} ]', HOT), + Line(), + *paragraph(t['talks'], lead=t['talks_lead']), + Line(), + joined([linked(CFP, f'[ {t["submit"]} ]'), linked(SCHEDULE, f'[ {t["schedule"]} ]')]), + Line(), + *paragraph(t['other'], lead=t['other_lead']), + ]), + Line(), + *box('{} {}'.format(*t['sections'][2][:2]), [ + *pairs(t['route'], label, links=[('BBBike.de', 'http://www.bbbike.de/')]), + Line(), + linked(MAP, f'[ {t["map"]} ]'), + ]), + Line(), + *footer(t['footer']), + ]) + + +def code_of_conduct(t): + return page([ + *box('Code of Conduct', [ + *paragraph(t['intro']), + Line(), + *bullets(t['rules']), + Line(), + *paragraph(t['house'], lead=t['house_lead']), + Line(), + *paragraph(t['problems'], lead=t['problems_lead']), + ]), + Line(), + *footer(t['footer']), + ]) + + +DE = { + 'page': '', 'coc': 'coc.html', + 'date': 'CCC Berlin · 28. – 29.11.2026', + 'sections': [(1, 'Infos', 'infos'), (2, 'Mitmachen', 'mitmachen'), (3, 'Anfahrt', 'anfahrt')], + 'intro': [ + 'Khaos im Kiez ist ein kleines Chaos-Event, back to the roots: inspiriert von anderen kleinen Chaos-Events. ' + 'Ein Wochenende zum Chillen und um die Seite von Chaos-Events zu erleben, für die bei größeren Events oft ' + 'keine Zeit mehr bleibt.', + 'Du kannst einen Talk oder Workshop halten, an deinen Projekten schrauben, gemeinsam hacken, löten, basteln ' + 'oder einfach vorbeikommen, zuhören und Leute kennenlernen. Alle sind willkommen, die Lust auf $Dinge, ' + 'Neugier und Chaos mitbringen.', + ], + 'infos': [ + ('Was', 'Khaos im Kiez (KiK)'), + ('Wann', 'Sa 28.11. – So 29.11.2026, 11:00 – 23:59'), + ('Wo', 'Marienstraße 11, 10117 Berlin'), + ('Wer', 'Chaos Computer Club Berlin'), + ('Preis', '0,00 € (Ticket trotzdem nötig, ~50 Plätze)'), + ('Fahrplan', 'cfp.berlin.ccc.de'), + ('Essen', 'Ewiges Frühstück, vegan'), + ('Barrierefrei', 'Nicht barrierefrei.'), + ('Regeln', 'Code of Conduct'), + ], + 'ticket_lead': 'Ticket:', + 'ticket': 'Anmeldung über den Ticketshop. Das Ticket ist kostenlos, aber die Plätze sind begrenzt.', + 'get_ticket': 'Ticket sichern', + 'talks_lead': 'Talks & Workshops:', + 'talks': 'Reiche deinen Beitrag im Call for Participation ein und schau dir später den Fahrplan an.', + 'submit': 'Talk einreichen', 'schedule': 'Fahrplan', + 'other_lead': 'Sonstiges:', + 'other': 'Du willst anders helfen oder hast Fragen? Schreib an aprl [at] berlin [dot] ccc [dot] de.', + 'route': [ + ('Adresse', 'Clubräume im Hinterhof der Marienstraße 11, 10117 Berlin'), + ('Koordinaten', '52,52194° N, 13,38261° O'), + ('Fahrrad', 'Im Innenhof gibt es eine begrenzte Zahl an Fahrradständern. Auf dem Weg liegen viele ' + 'Fahrradstraßen, nutz die am besten, z. B. mit BBBike.de.'), + ('ÖPNV', 'Der Club liegt direkt beim S+U-Bahnhof Friedrichstraße (auch Regionalbahnen). Vom oberirdischen ' + 'S-Bahn-Steig (S3/S5/S7) nimmst du den Ausgang Schiffbauerdamm und gehst unter der Bahnbrücke über ' + 'die Spree. Über die Albrechtstraße kommst du zur Marienstraße.'), + ('Fernverkehr', 'Aussteigen in Berlin Hauptbahnhof, dann mit S-Bahn oder Regionalbahn Richtung Osten eine ' + 'Station bis Friedrichstraße. Bahnhof Richtung Spree verlassen, über die Fußgängerbrücke und ' + 'der Albrechtstraße bis zur Stichstraße Marienstraße folgen.'), + ('Flugzeug', 'BER: Airport Express (RE7, RB14) oder S9 bis Friedrichstraße, alternativ FEX bis Hauptbahnhof ' + '(dann wie Fernverkehr). Achtung: Terminal 5 (früher SXF) ist nicht mit dem Rest des BER ' + 'verbunden, dort fährt nur die S9. Flugplatz Strausberg (EDAY): S7 direkt bis Friedrichstraße.'), + ('Auto', 'Zufahrt von Hauptbahnhof oder Brandenburger Tor über die Luisenstraße. Von der Friedrichstraße ' + 'entweder über Schiffbauerdamm und Albrechtstraße (Außengastronomie und Kopfsteinpflaster) oder ' + 'über Reinhardstraße und Luisenstraße (die Albrechtstraße ist nur in Gegenrichtung befahrbar).'), + ('Parken', 'Achtung: Es gibt kaum Parkplätze, und die Marienstraße und alle umliegenden Straßen sind ' + 'parkraumbewirtschaftet.'), + ], + 'map': 'Karte (OpenStreetMap)', + 'footer': [('Impressum', IMPRESSUM), ('CCC Berlin', 'https://berlin.ccc.de/')], +} + +EN = { + 'page': 'en.html', 'coc': 'coc-en.html', + 'date': 'CCC Berlin · 2026-11-28 – 2026-11-29', + 'sections': [(1, 'Info', 'infos'), (2, 'Join in', 'join'), (3, 'Getting here', 'getting-here')], + 'intro': [ + 'Khaos im Kiez is a small chaos event, back to the roots: inspired by other small chaos events. A weekend to ' + 'chill and to experience the side of chaos events that often gets no time at larger events.', + 'Give a talk or workshop, work on your projects, hack together, solder, tinker, or simply drop by, listen and ' + 'meet people. Everyone who brings a love of $things, curiosity and a bit of chaos is welcome.', + ], + 'infos': [ + ('What', 'Khaos im Kiez (KiK)'), + ('When', 'Sat 2026-11-28 – Sun 2026-11-29, 11:00 – 23:59'), + ('Where', 'Marienstraße 11, 10117 Berlin, Germany'), + ('Who', 'Chaos Computer Club Berlin'), + ('Price', '€0.00 (ticket still required, ~50 seats)'), + ('Schedule', 'cfp.berlin.ccc.de'), + ('Food', 'Eternal breakfast, vegan'), + ('Accessibility', 'Not accessible.'), + ('Rules', 'Code of Conduct'), + ], + 'ticket_lead': 'Ticket:', + 'ticket': 'Register via the ticket shop. The ticket is free, but seats are limited.', + 'get_ticket': 'Get ticket', + 'talks_lead': 'Talks & workshops:', + 'talks': 'Submit your proposal via the call for participation and check the schedule later.', + 'submit': 'Submit a talk', 'schedule': 'Schedule', + 'other_lead': 'Other:', + 'other': 'Want to help otherwise or have questions? Write to aprl [at] berlin [dot] ccc [dot] de.', + 'route': [ + ('Address', 'Club rooms in the back yard of Marienstraße 11, 10117 Berlin'), + ('Coordinates', '52.52194° N, 13.38261° E'), + ('Bicycle', 'A limited number of bike racks are in the courtyard. Many bicycle streets lead there, preferably ' + 'use those, e.g. with BBBike.de.'), + ('Local transit', 'The club is right next to S+U Friedrichstraße (regional trains stop there too). From the ' + 'elevated S-Bahn platform (S3/S5/S7) take the Schiffbauerdamm exit and walk across the Spree ' + 'beneath the railway bridge. Albrechtstraße leads to Marienstraße.'), + ('Long distance', 'Get off at Berlin Hauptbahnhof, then take any S-Bahn or regional train eastbound one stop ' + 'to Friedrichstraße. Leave the station towards the Spree, cross the footbridge and follow ' + 'Albrechtstraße to the dead-end Marienstraße.'), + ('Air', 'BER: Airport Express (RE7, RB14) or S9 to Friedrichstraße, or FEX to Hauptbahnhof (then as above). ' + 'Note: Terminal 5 (formerly SXF) is not connected to the rest of BER, only the S9 runs there. ' + 'Strausberg airfield (EDAY): S7 direct to Friedrichstraße.'), + ('Car', 'Access from Hauptbahnhof or Brandenburger Tor via Luisenstraße. From Friedrichstraße either via ' + 'Schiffbauerdamm and Albrechtstraße (outdoor seating and cobblestones) or via Reinhardstraße and ' + 'Luisenstraße (Albrechtstraße is one-way the other direction).'), + ('Parking', 'Warning: parking is scarce, and Marienstraße and all surrounding streets are subject to paid ' + 'parking zones.'), + ], + 'map': 'Map (OpenStreetMap)', + 'footer': [('Legal notice', IMPRESSUM), ('CCC Berlin', 'https://berlin.ccc.de/')], +} + +COC_DE = { + 'intro': 'Khaos im Kiez ist eine Veranstaltung des Chaos Computer Club Berlin e.V. (CCCB). Damit sich alle ' + 'wohlfühlen, gelten diese Regeln für alle Teilnehmenden, Vortragenden und Helfenden.', + 'rules': [ + ('Sei nett zueinander.', 'Geh respektvoll und freundlich miteinander um, auch wenn du anderer Meinung bist.'), + ('Keine Diskriminierung.', 'Rassismus, Sexismus, Queerfeindlichkeit, Ableismus und andere menschenverachtende ' + 'Haltungen haben hier keinen Platz.'), + ('Keine Belästigung.', 'Dazu gehören Beleidigungen, Bedrohungen, Stalking, unerwünschte körperliche ' + 'Berührungen und unerwünschte sexuelle Aufmerksamkeit. Ein Nein ist ein Nein.'), + ('Frag vor dem Fotografieren.', 'Fotos, Video- und Tonaufnahmen von Personen nur mit deren Einverständnis. ' + 'Das gilt auch für Talks und Workshops.'), + ('Achte auf Geräte und Eigentum.', 'Fass fremde Geräte nicht ohne Erlaubnis an. Geh pfleglich mit den Räumen ' + 'und dem Inventar um.'), + ('Sei neugierig, nicht übergriffig.', 'Chaos ja, Grenzenüberschreitungen nein.'), + ], + 'house_lead': 'Hausrecht:', + 'house': 'Die Orga hat Hausrecht. Bei Verstößen gegen diese Regeln kann sie Verwarnungen aussprechen, Personen ' + 'der Veranstaltung verweisen oder ein Hausverbot erteilen. Den Anweisungen der Orga ist Folge zu leisten.', + 'problems_lead': 'Probleme?', + 'problems': 'Wenn dir etwas passiert oder du etwas beobachtest, sprich eine Person aus der Orga an oder schreib an ' + 'aprl [at] berlin [dot] ccc [dot] de. Hinweise werden vertraulich behandelt.', + 'footer': [('Startseite', SITE), ('Impressum', IMPRESSUM)], +} + +COC_EN = { + 'intro': 'Khaos im Kiez is an event of the Chaos Computer Club Berlin e.V. (CCCB). To make everyone feel ' + 'comfortable, these rules apply to all attendees, speakers and helpers.', + 'rules': [ + ('Be nice to each other.', 'Treat each other respectfully and kindly, even when you disagree.'), + ('No discrimination.', 'Racism, sexism, queerphobia, ableism and other hateful attitudes have no place here.'), + ('No harassment.', 'This includes insults, threats, stalking, unwanted physical contact and unwanted sexual ' + 'attention. No means no.'), + ('Ask before taking pictures.', 'Photos, video and audio recordings of people only with their consent. This ' + 'also applies to talks and workshops.'), + ('Respect devices and property.', "Do not touch other people's devices without permission. Treat the rooms " + 'and furniture with care.'), + ('Be curious, not intrusive.', 'Chaos yes, crossing boundaries no.'), + ], + 'house_lead': 'House rules:', + 'house': 'The organizers have the right to exclude people from the premises (Hausrecht). In case of violations ' + "they may issue warnings, ask people to leave, or ban them from the event. Follow the organizers' " + 'instructions.', + 'problems_lead': 'Problems?', + 'problems': 'If something happens to you or you notice something, talk to a member of the organizing team or ' + 'write to aprl [at] berlin [dot] ccc [dot] de. Reports are treated confidentially.', + 'footer': [('Home', f'{SITE}en.html'), ('Legal notice', IMPRESSUM)], +} + +out = pathlib.Path(__file__).parent.parent / 'resources' / 'home' +out.mkdir(parents=True, exist_ok=True) +for name, text in [('README', readme(DE)), ('README.en', readme(EN)), + ('CODE_OF_CONDUCT', code_of_conduct(COC_DE)), ('CODE_OF_CONDUCT.en', code_of_conduct(COC_EN))]: + (out / name).write_text(text, encoding='utf-8') diff --git a/src/components/Prompt.astro b/src/components/Prompt.astro new file mode 100644 index 0000000..1178e26 --- /dev/null +++ b/src/components/Prompt.astro @@ -0,0 +1 @@ +
root@khaos-im-kiez:~#
visitor@khaos-im-kiez:~$ cat CODE_OF_CONDUCT.en
+--- +import Layout from '../layouts/Layout.astro'; +--- +visitor@khaos-im-kiez:~$ cat CODE_OF_CONDUCT
+--- +import Layout from '../layouts/Layout.astro'; +--- +visitor@khaos-im-kiez:~$ cat README.en
+--- +import Layout from '../layouts/Layout.astro'; +--- +
@@ -98,9 +93,6 @@
-visitor@khaos-im-kiez:~$ cat README
+--- +import Layout from '../layouts/Layout.astro'; +--- +
@@ -102,117 +97,6 @@
Impressum ·
CCC Berlin
- visitor@khaos-im-kiez:~$
-