From f3de34d0c753d9cbf8196ccca3aecccd22c014a0 Mon Sep 17 00:00:00 2001 From: Mia Pigal Date: Fri, 30 Jan 2026 16:10:08 -0500 Subject: [PATCH 01/12] fix: don't require database config to start gsw --- cmd/gsw_service.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmd/gsw_service.go b/cmd/gsw_service.go index 07cef6c..e3e61b4 100644 --- a/cmd/gsw_service.go +++ b/cmd/gsw_service.go @@ -128,12 +128,6 @@ func readConfig() (*viper.Viper, int) { logger.Warn("Config file not found, reading config from environment variables") } } - if !config.IsSet("database_host_name") { - logger.Panic("Error reading GSW config: database_host_name not set...") - } - if !config.IsSet("database_port_number") { - logger.Panic("Error reading GSW config: database_port_number not set...") - } return config, *doPprof } From b592977b5e2f3fee6f112268cb954fec05751bb4 Mon Sep 17 00:00:00 2001 From: Mia Pigal Date: Sun, 1 Feb 2026 12:48:14 -0500 Subject: [PATCH 02/12] svelte boilerplate --- ui/.gitignore | 24 + ui/README.md | 47 + ui/eslint.config.ts | 82 ++ ui/index.html | 12 + ui/package.json | 32 + ui/pnpm-lock.yaml | 2588 +++++++++++++++++++++++++++++++++++++++++ ui/src/App.svelte | 28 + ui/src/index.css | 1 + ui/src/main.ts | 9 + ui/src/svelte.d.ts | 1 + ui/svelte.config.js | 8 + ui/tsconfig.app.json | 21 + ui/tsconfig.json | 7 + ui/tsconfig.node.json | 26 + ui/vite.config.ts | 11 + 15 files changed, 2897 insertions(+) create mode 100644 ui/.gitignore create mode 100644 ui/README.md create mode 100644 ui/eslint.config.ts create mode 100644 ui/index.html create mode 100644 ui/package.json create mode 100644 ui/pnpm-lock.yaml create mode 100644 ui/src/App.svelte create mode 100644 ui/src/index.css create mode 100644 ui/src/main.ts create mode 100644 ui/src/svelte.d.ts create mode 100644 ui/svelte.config.js create mode 100644 ui/tsconfig.app.json create mode 100644 ui/tsconfig.json create mode 100644 ui/tsconfig.node.json create mode 100644 ui/vite.config.ts diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 0000000..e6cd94f --- /dev/null +++ b/ui/README.md @@ -0,0 +1,47 @@ +# Svelte + TS + Vite + +This template should help get you started developing with Svelte and TypeScript in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). + +## Need an official Svelte framework? + +Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. + +## Technical considerations + +**Why use this over SvelteKit?** + +- It brings its own routing solution which might not be preferable for some users. +- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. + +This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. + +Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. + +**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** + +Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. + +**Why include `.vscode/extensions.json`?** + +Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. + +**Why enable `allowJs` in the TS template?** + +While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. + +**Why is HMR not preserving my local component state?** + +HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). + +If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. + +```ts +// store.ts +// An extremely simple external store +import { writable } from 'svelte/store' +export default writable(0) +``` diff --git a/ui/eslint.config.ts b/ui/eslint.config.ts new file mode 100644 index 0000000..7980bdc --- /dev/null +++ b/ui/eslint.config.ts @@ -0,0 +1,82 @@ +import globals from "globals"; +import svelte from "eslint-plugin-svelte"; +import tseslint from "typescript-eslint"; +import svelteConfig from "./svelte.config.js"; +import stylistic from "@stylistic/eslint-plugin"; +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + ...tseslint.configs.recommended, + ...svelte.configs.recommended, + { + plugins: { + "@stylistic": stylistic, + }, + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, // Add this if you are using SvelteKit in non-SPA mode + }, + }, + }, + { + files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"], + // See more details at: https://typescript-eslint.io/packages/parser/ + languageOptions: { + parserOptions: { + projectService: true, + extraFileExtensions: [".svelte"], // Add support for additional file extensions, such as .svelte + parser: tseslint.parser, + // Specify a parser for each language, if needed: + // parser: { + // ts: ts.parser, + // js: espree, // Use espree for .js files (add: import espree from 'espree') + // typescript: ts.parser + // }, + + // We recommend importing and specifying svelte.config.js. + // By doing so, some rules in eslint-plugin-svelte will automatically read the configuration and adjust their behavior accordingly. + // While certain Svelte settings may be statically loaded from svelte.config.js even if you don’t specify it, + // explicitly specifying it ensures better compatibility and functionality. + // + // If non-serializable properties are included, running ESLint with the --cache flag will fail. + // In that case, please remove the non-serializable properties. (e.g. `svelteConfig: { ...svelteConfig, kit: { ...svelteConfig.kit, typescript: undefined }}`) + svelteConfig + }, + } + }, + // { + // "overrides": [ + // { + // "files": ["*.svelte"], + // "rules": { + // "svelte/indent": [ + // "error", + // { indent: 4 }, + // ], + // "indent": "off" + // } + // } + // ], + + // }, + { + rules: { + "indent": [ + "error", + 4, + ], + "svelte/indent": [ + "error", + { indent: 4 }, + ], + + "linebreak-style": ["error", "unix"], + "@stylistic/quotes": ["error", "double"], + "@stylistic/semi": "error", + }, + }, +]; diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..dfd9bbe --- /dev/null +++ b/ui/index.html @@ -0,0 +1,12 @@ + + + + + + GSW UI + + +
+ + + diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 0000000..d0334a5 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,32 @@ +{ + "name": "gsw-ui", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" + }, + "devDependencies": { + "@eslint/js": "^9.39.2", + "@stylistic/eslint-plugin": "^5.7.1", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@tailwindcss/vite": "^4.1.18", + "@tsconfig/svelte": "^5.0.6", + "@types/node": "^24.10.1", + "eslint": "^9.39.2", + "eslint-plugin-svelte": "^3.14.0", + "globals": "^17.2.0", + "svelte": "^5.43.8", + "svelte-check": "^4.3.4", + "tailwindcss": "^4.1.18", + "typescript": "~5.9.3", + "typescript-eslint": "^8.54.0", + "vite": "^7.2.4" + }, + "dependencies": { + "mqtt": "^5.14.1" + } +} diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml new file mode 100644 index 0000000..bbdf7e0 --- /dev/null +++ b/ui/pnpm-lock.yaml @@ -0,0 +1,2588 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + mqtt: + specifier: ^5.14.1 + version: 5.14.1 + devDependencies: + '@eslint/js': + specifier: ^9.39.2 + version: 9.39.2 + '@stylistic/eslint-plugin': + specifier: ^5.7.1 + version: 5.7.1(eslint@9.39.2(jiti@2.6.1)) + '@sveltejs/vite-plugin-svelte': + specifier: ^6.2.1 + version: 6.2.4(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)) + '@tailwindcss/vite': + specifier: ^4.1.18 + version: 4.1.18(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)) + '@tsconfig/svelte': + specifier: ^5.0.6 + version: 5.0.6 + '@types/node': + specifier: ^24.10.1 + version: 24.10.9 + eslint: + specifier: ^9.39.2 + version: 9.39.2(jiti@2.6.1) + eslint-plugin-svelte: + specifier: ^3.14.0 + version: 3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.49.1) + globals: + specifier: ^17.2.0 + version: 17.2.0 + svelte: + specifier: ^5.43.8 + version: 5.49.1 + svelte-check: + specifier: ^4.3.4 + version: 4.3.5(picomatch@4.0.3)(svelte@5.49.1)(typescript@5.9.3) + tailwindcss: + specifier: ^4.1.18 + version: 4.1.18 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.54.0 + version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + vite: + specifier: ^7.2.4 + version: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2) + +packages: + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + cpu: [x64] + os: [win32] + + '@stylistic/eslint-plugin@5.7.1': + resolution: {integrity: sha512-zjTUwIsEfT+k9BmXwq1QEFYsb4afBlsI1AXFyWQBgggMzwBFOuu92pGrE5OFx90IOjNl+lUbQoTG7f8S0PkOdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=9.0.0' + + '@sveltejs/acorn-typescript@1.0.8': + resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/vite-plugin-svelte-inspector@5.0.2': + resolution: {integrity: sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@sveltejs/vite-plugin-svelte@6.2.4': + resolution: {integrity: sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.18': + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tsconfig/svelte@5.0.6': + resolution: {integrity: sha512-yGxYL0I9eETH1/DR9qVJey4DAsCdeau4a9wYPKuXfEhm8lFO8wg+LLYJjIpAm6Fw7HSlhepPhYPDop75485yWQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@24.10.9': + resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} + + '@types/readable-stream@4.0.23': + resolution: {integrity: sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.54.0': + resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.54.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.54.0': + resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.54.0': + resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.54.0': + resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.54.0': + resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.54.0': + resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.54.0': + resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.54.0': + resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.54.0': + resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.54.0': + resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bl@6.1.6: + resolution: {integrity: sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + broker-factory@3.1.13: + resolution: {integrity: sha512-H2VALe31mEtO/SRcNp4cUU5BAm1biwhc/JaF77AigUuni/1YT0FLCJfbUxwIEs9y6Kssjk2fmXgf+Y9ALvmKlw==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commist@3.2.0: + resolution: {integrity: sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + engines: {node: '>=10.13.0'} + + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-svelte@3.14.0: + resolution: {integrity: sha512-Isw0GvaMm0yHxAj71edAdGFh28ufYs+6rk2KlbbZphnqZAzrH3Se3t12IFh2H9+1F/jlDhBBL4oiOJmLqmYX0g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.1 || ^9.0.0 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrap@2.2.2: + resolution: {integrity: sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-unique-numbers@9.0.26: + resolution: {integrity: sha512-3Mtq8p1zQinjGyWfKeuBunbuFoixG72AUkk4VvzbX4ykCW9Q4FzRaNyIlfQhUjnKw2ARVP+/CKnoyr6wfHftig==} + engines: {node: '>=18.2.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + globals@17.2.0: + resolution: {integrity: sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==} + engines: {node: '>=18'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-sdsl@4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + known-css-properties@0.37.0: + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mqtt-packet@9.0.2: + resolution: {integrity: sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==} + + mqtt@5.14.1: + resolution: {integrity: sha512-NxkPxE70Uq3Ph7goefQa7ggSsVzHrayCD0OyxlJgITN/EbzlZN+JEPmaAZdxP1LsIT5FamDyILoQTF72W7Nnbw==} + engines: {node: '>=16.0.0'} + hasBin: true + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + number-allocator@1.0.14: + resolution: {integrity: sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss-load-config@3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + svelte-check@4.3.5: + resolution: {integrity: sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==} + engines: {node: '>= 18.0.0'} + hasBin: true + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: '>=5.0.0' + + svelte-eslint-parser@1.4.1: + resolution: {integrity: sha512-1eqkfQ93goAhjAXxZiu1SaKI9+0/sxp4JIWQwUpsz7ybehRE5L8dNuz7Iry7K22R47p5/+s9EM+38nHV2OlgXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.24.0} + peerDependencies: + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + svelte@5.49.1: + resolution: {integrity: sha512-jj95WnbKbXsXXngYj28a4zx8jeZx50CN/J4r0CEeax2pbfdsETv/J1K8V9Hbu3DCXnpHz5qAikICuxEooi7eNQ==} + engines: {node: '>=18'} + + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript-eslint@8.54.0: + resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.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 + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + worker-factory@7.0.48: + resolution: {integrity: sha512-CGmBy3tJvpBPjUvb0t4PrpKubUsfkI1Ohg0/GGFU2RvA9j/tiVYwKU8O7yu7gH06YtzbeJLzdUR29lmZKn5pag==} + + worker-timers-broker@8.0.15: + resolution: {integrity: sha512-Te+EiVUMzG5TtHdmaBZvBrZSFNauym6ImDaCAnzQUxvjnw+oGjMT2idmAOgDy30vOZMLejd0bcsc90Axu6XPWA==} + + worker-timers-worker@9.0.13: + resolution: {integrity: sha512-qjn18szGb1kjcmh2traAdki1eiIS5ikFo+L90nfMOvSRpuDw1hAcR1nzkP2+Hkdqz5thIRnfuWx7QSpsEUsA6Q==} + + worker-timers@8.0.29: + resolution: {integrity: sha512-9jk0MWHhWAZ2xlJPXr45oe5UF/opdpfZrY0HtyPizWuJ+ce1M3IYk/4IIdGct3kn9Ncfs+tkZt3w1tU6KW2Fsg==} + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + +snapshots: + + '@babel/runtime@7.28.6': {} + + '@esbuild/aix-ppc64@0.27.2': + optional: true + + '@esbuild/android-arm64@0.27.2': + optional: true + + '@esbuild/android-arm@0.27.2': + optional: true + + '@esbuild/android-x64@0.27.2': + optional: true + + '@esbuild/darwin-arm64@0.27.2': + optional: true + + '@esbuild/darwin-x64@0.27.2': + optional: true + + '@esbuild/freebsd-arm64@0.27.2': + optional: true + + '@esbuild/freebsd-x64@0.27.2': + optional: true + + '@esbuild/linux-arm64@0.27.2': + optional: true + + '@esbuild/linux-arm@0.27.2': + optional: true + + '@esbuild/linux-ia32@0.27.2': + optional: true + + '@esbuild/linux-loong64@0.27.2': + optional: true + + '@esbuild/linux-mips64el@0.27.2': + optional: true + + '@esbuild/linux-ppc64@0.27.2': + optional: true + + '@esbuild/linux-riscv64@0.27.2': + optional: true + + '@esbuild/linux-s390x@0.27.2': + optional: true + + '@esbuild/linux-x64@0.27.2': + optional: true + + '@esbuild/netbsd-arm64@0.27.2': + optional: true + + '@esbuild/netbsd-x64@0.27.2': + optional: true + + '@esbuild/openbsd-arm64@0.27.2': + optional: true + + '@esbuild/openbsd-x64@0.27.2': + optional: true + + '@esbuild/openharmony-arm64@0.27.2': + optional: true + + '@esbuild/sunos-x64@0.27.2': + optional: true + + '@esbuild/win32-arm64@0.27.2': + optional: true + + '@esbuild/win32-ia32@0.27.2': + optional: true + + '@esbuild/win32-x64@0.27.2': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.2': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-x64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.57.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.57.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.57.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.57.1': + optional: true + + '@stylistic/eslint-plugin@5.7.1(eslint@9.39.2(jiti@2.6.1))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/types': 8.54.0 + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + estraverse: 5.3.0 + picomatch: 4.0.3 + + '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)) + obug: 2.1.1 + svelte: 5.49.1 + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2) + + '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.1)(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)) + deepmerge: 4.3.1 + magic-string: 0.30.21 + obug: 2.1.1 + svelte: 5.49.1 + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)) + + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.4 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2) + + '@tsconfig/svelte@5.0.6': {} + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@24.10.9': + dependencies: + undici-types: 7.16.0 + + '@types/readable-stream@4.0.23': + dependencies: + '@types/node': 24.10.9 + + '@types/ws@8.18.1': + dependencies: + '@types/node': 24.10.9 + + '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.54.0 + eslint: 9.39.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.54.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) + '@typescript-eslint/types': 8.54.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.54.0': + dependencies: + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 + + '@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.54.0': {} + + '@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.54.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.54.0': + dependencies: + '@typescript-eslint/types': 8.54.0 + eslint-visitor-keys: 4.2.1 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + bl@6.1.6: + dependencies: + '@types/readable-stream': 4.0.23 + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 4.7.0 + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + broker-factory@3.1.13: + dependencies: + '@babel/runtime': 7.28.6 + fast-unique-numbers: 9.0.26 + tslib: 2.8.1 + worker-factory: 7.0.48 + + buffer-from@1.1.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commist@3.2.0: {} + + concat-map@0.0.1: {} + + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + detect-libc@2.1.2: {} + + devalue@5.6.2: {} + + enhanced-resolve@5.18.4: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + + escape-string-regexp@4.0.0: {} + + eslint-plugin-svelte@3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.49.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@jridgewell/sourcemap-codec': 1.5.5 + eslint: 9.39.2(jiti@2.6.1) + esutils: 2.0.3 + globals: 16.5.0 + known-css-properties: 0.37.0 + postcss: 8.5.6 + postcss-load-config: 3.1.4(postcss@8.5.6) + postcss-safe-parser: 7.0.1(postcss@8.5.6) + semver: 7.7.3 + svelte-eslint-parser: 1.4.1(svelte@5.49.1) + optionalDependencies: + svelte: 5.49.1 + transitivePeerDependencies: + - ts-node + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + esm-env@1.2.2: {} + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrap@2.2.2: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + event-target-shim@5.0.1: {} + + events@3.3.0: {} + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-unique-numbers@9.0.26: + dependencies: + '@babel/runtime': 7.28.6 + tslib: 2.8.1 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + fsevents@2.3.3: + optional: true + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.5.0: {} + + globals@17.2.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + help-me@5.0.0: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ip-address@10.1.0: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + isexe@2.0.0: {} + + jiti@2.6.1: {} + + js-sdsl@4.3.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + known-css-properties@0.37.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lilconfig@2.1.0: {} + + locate-character@3.0.0: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lru-cache@10.4.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mqtt-packet@9.0.2: + dependencies: + bl: 6.1.6 + debug: 4.4.3 + process-nextick-args: 2.0.1 + transitivePeerDependencies: + - supports-color + + mqtt@5.14.1: + dependencies: + '@types/readable-stream': 4.0.23 + '@types/ws': 8.18.1 + commist: 3.2.0 + concat-stream: 2.0.0 + debug: 4.4.3 + help-me: 5.0.0 + lru-cache: 10.4.3 + minimist: 1.2.8 + mqtt-packet: 9.0.2 + number-allocator: 1.0.14 + readable-stream: 4.7.0 + rfdc: 1.4.1 + socks: 2.8.7 + split2: 4.2.0 + worker-timers: 8.0.29 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + mri@1.2.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + number-allocator@1.0.14: + dependencies: + debug: 4.4.3 + js-sdsl: 4.3.0 + transitivePeerDependencies: + - supports-color + + obug@2.1.1: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss-load-config@3.1.4(postcss@8.5.6): + dependencies: + lilconfig: 2.1.0 + yaml: 1.10.2 + optionalDependencies: + postcss: 8.5.6 + + postcss-safe-parser@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-scss@4.0.9(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + punycode@2.3.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdirp@4.1.2: {} + + resolve-from@4.0.0: {} + + rfdc@1.4.1: {} + + rollup@4.57.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 + fsevents: 2.3.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + safe-buffer@5.2.1: {} + + semver@7.7.3: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + smart-buffer@4.2.0: {} + + socks@2.8.7: + dependencies: + ip-address: 10.1.0 + smart-buffer: 4.2.0 + + source-map-js@1.2.1: {} + + split2@4.2.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + svelte-check@4.3.5(picomatch@4.0.3)(svelte@5.49.1)(typescript@5.9.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + chokidar: 4.0.3 + fdir: 6.5.0(picomatch@4.0.3) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.49.1 + typescript: 5.9.3 + transitivePeerDependencies: + - picomatch + + svelte-eslint-parser@1.4.1(svelte@5.49.1): + dependencies: + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + postcss: 8.5.6 + postcss-scss: 4.0.9(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + optionalDependencies: + svelte: 5.49.1 + + svelte@5.49.1: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + devalue: 5.6.2 + esm-env: 1.2.2 + esrap: 2.2.2 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.21 + zimmerframe: 1.1.4 + + tailwindcss@4.1.18: {} + + tapable@2.3.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typedarray@0.0.6: {} + + typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + undici-types@7.16.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.9 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + + vitefu@1.1.1(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)): + optionalDependencies: + vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2) + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + worker-factory@7.0.48: + dependencies: + '@babel/runtime': 7.28.6 + fast-unique-numbers: 9.0.26 + tslib: 2.8.1 + + worker-timers-broker@8.0.15: + dependencies: + '@babel/runtime': 7.28.6 + broker-factory: 3.1.13 + fast-unique-numbers: 9.0.26 + tslib: 2.8.1 + worker-timers-worker: 9.0.13 + + worker-timers-worker@9.0.13: + dependencies: + '@babel/runtime': 7.28.6 + tslib: 2.8.1 + worker-factory: 7.0.48 + + worker-timers@8.0.29: + dependencies: + '@babel/runtime': 7.28.6 + tslib: 2.8.1 + worker-timers-broker: 8.0.15 + worker-timers-worker: 9.0.13 + + ws@8.19.0: {} + + yaml@1.10.2: {} + + yocto-queue@0.1.0: {} + + zimmerframe@1.1.4: {} diff --git a/ui/src/App.svelte b/ui/src/App.svelte new file mode 100644 index 0000000..9517d80 --- /dev/null +++ b/ui/src/App.svelte @@ -0,0 +1,28 @@ + + +
+
+ {#each state.keys() as topic (topic)} +
{topic}: {state.get(topic)}
+ {/each} +
+
diff --git a/ui/src/index.css b/ui/src/index.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/ui/src/index.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/ui/src/main.ts b/ui/src/main.ts new file mode 100644 index 0000000..aef7ba0 --- /dev/null +++ b/ui/src/main.ts @@ -0,0 +1,9 @@ +import { mount } from "svelte"; +import "./index.css"; +import App from "./App.svelte"; + +const app = mount(App, { + target: document.getElementById("app")!, +}); + +export default app; diff --git a/ui/src/svelte.d.ts b/ui/src/svelte.d.ts new file mode 100644 index 0000000..a51dd09 --- /dev/null +++ b/ui/src/svelte.d.ts @@ -0,0 +1 @@ +declare module "*.svelte" diff --git a/ui/svelte.config.js b/ui/svelte.config.js new file mode 100644 index 0000000..96b3455 --- /dev/null +++ b/ui/svelte.config.js @@ -0,0 +1,8 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import("@sveltejs/vite-plugin-svelte").SvelteConfig} */ +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/ui/tsconfig.app.json b/ui/tsconfig.app.json new file mode 100644 index 0000000..31c18cf --- /dev/null +++ b/ui/tsconfig.app.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "types": ["svelte", "vite/client"], + "noEmit": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "moduleDetection": "force" + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] +} diff --git a/ui/tsconfig.json b/ui/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/ui/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/ui/tsconfig.node.json b/ui/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/ui/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/ui/vite.config.ts b/ui/vite.config.ts new file mode 100644 index 0000000..a109e7e --- /dev/null +++ b/ui/vite.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import tailwindcss from "@tailwindcss/vite"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + svelte(), + tailwindcss(), + ], +}); From 424f38f7ddd8c2734a0797e41db13a569282798e Mon Sep 17 00:00:00 2001 From: Mia Pigal Date: Sun, 1 Feb 2026 12:57:37 -0500 Subject: [PATCH 03/12] add documentation --- ui/README.md | 50 ++++++++------------------------------------------ 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/ui/README.md b/ui/README.md index e6cd94f..6c9be9a 100644 --- a/ui/README.md +++ b/ui/README.md @@ -1,47 +1,13 @@ -# Svelte + TS + Vite +# `ui` -This template should help get you started developing with Svelte and TypeScript in Vite. +Ground station UI and overlays implemented in [Svelte](https://svelte.dev/). -## Recommended IDE Setup +Communicates with GSW through the `mqtt_producer` app and an MQTT server. This project uses [`pnpm`](https://pnpm.io/) over `npm` for its performance benefits. -[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). +## Development -## Need an official Svelte framework? - -Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. - -## Technical considerations - -**Why use this over SvelteKit?** - -- It brings its own routing solution which might not be preferable for some users. -- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. - -This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. - -Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. - -**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** - -Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. - -**Why include `.vscode/extensions.json`?** - -Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. - -**Why enable `allowJs` in the TS template?** - -While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. - -**Why is HMR not preserving my local component state?** - -HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). - -If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. - -```ts -// store.ts -// An extremely simple external store -import { writable } from 'svelte/store' -export default writable(0) +```shell +docker compose -f compose-services.yaml up --build +go run ./cmd/mqtt_producer +pnpm run dev ``` From eec9bcc2d2f0a5e7905af29e709eec30dd3df183 Mon Sep 17 00:00:00 2001 From: Mia Pigal Date: Sun, 1 Feb 2026 13:11:48 -0500 Subject: [PATCH 04/12] fix: clearer docs --- ui/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/README.md b/ui/README.md index 6c9be9a..a06f6dc 100644 --- a/ui/README.md +++ b/ui/README.md @@ -7,7 +7,11 @@ Communicates with GSW through the `mqtt_producer` app and an MQTT server. This p ## Development ```shell +# mosquitto container docker compose -f compose-services.yaml up --build + go run ./cmd/mqtt_producer -pnpm run dev + +# ui development server +cd ui/ && pnpm run dev ``` From 1aefb235506888416b441a5b639971921753ed03 Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 2 Apr 2026 18:50:59 -0400 Subject: [PATCH 05/12] feat: map that maps to aliflux --- ui/package.json | 2 + ui/pnpm-lock.yaml | 241 ++ ui/src/App.svelte | 63 +- ui/src/stores.ts | 85 + ui/src/style.aliflux.json | 40 + ui/src/style.json | 5896 ++++++++++++++++++++++++++ ui/src/types/svelte-maplibre-gl.d.ts | 7 + ui/tsconfig.app.json | 4 +- 8 files changed, 6318 insertions(+), 20 deletions(-) create mode 100644 ui/src/stores.ts create mode 100644 ui/src/style.aliflux.json create mode 100644 ui/src/style.json create mode 100644 ui/src/types/svelte-maplibre-gl.d.ts diff --git a/ui/package.json b/ui/package.json index d0334a5..ea02d2e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -21,12 +21,14 @@ "globals": "^17.2.0", "svelte": "^5.43.8", "svelte-check": "^4.3.4", + "svelte-maplibre-gl": "^1.0.3", "tailwindcss": "^4.1.18", "typescript": "~5.9.3", "typescript-eslint": "^8.54.0", "vite": "^7.2.4" }, "dependencies": { + "maplibre-gl": "^5.19.0", "mqtt": "^5.14.1" } } diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index bbdf7e0..91256fc 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + maplibre-gl: + specifier: ^5.19.0 + version: 5.19.0 mqtt: specifier: ^5.14.1 version: 5.14.1 @@ -45,6 +48,9 @@ importers: svelte-check: specifier: ^4.3.4 version: 4.3.5(picomatch@4.0.3)(svelte@5.49.1)(typescript@5.9.3) + svelte-maplibre-gl: + specifier: ^1.0.3 + version: 1.0.3(maplibre-gl@5.19.0)(svelte@5.49.1) tailwindcss: specifier: ^4.1.18 version: 4.1.18 @@ -290,6 +296,43 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mapbox/geojson-rewind@0.5.2': + resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} + hasBin: true + + '@mapbox/jsonlint-lines-primitives@2.0.2': + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + + '@mapbox/point-geometry@1.1.0': + resolution: {integrity: sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==} + + '@mapbox/tiny-sdf@2.0.7': + resolution: {integrity: sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==} + + '@mapbox/unitbezier@0.0.1': + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + + '@mapbox/vector-tile@2.0.4': + resolution: {integrity: sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==} + + '@mapbox/whoots-js@3.1.0': + resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} + engines: {node: '>=6.0.0'} + + '@maplibre/geojson-vt@5.0.4': + resolution: {integrity: sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==} + + '@maplibre/maplibre-gl-style-spec@24.6.0': + resolution: {integrity: sha512-+lxMYE+DvInshwVrqSQ3CkW9YRwVlRXeDzfthVOa1c9pwK5d7YgCwhgFwlSmjJLvTXn4gL8EvPUGT620sk2Pzg==} + hasBin: true + + '@maplibre/mlt@1.1.6': + resolution: {integrity: sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw==} + + '@maplibre/vt-pbf@4.3.0': + resolution: {integrity: sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w==} + '@rollup/rollup-android-arm-eabi@4.57.1': resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] @@ -324,66 +367,79 @@ packages: resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} @@ -479,24 +535,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -537,6 +597,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -546,6 +609,9 @@ packages: '@types/readable-stream@4.0.23': resolution: {integrity: sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==} + '@types/supercluster@7.1.3': + resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -729,6 +795,9 @@ packages: devalue@5.6.2: resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + earcut@3.0.2: + resolution: {integrity: sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==} + enhanced-resolve@5.18.4: resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} @@ -850,6 +919,13 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + gl-matrix@3.4.4: + resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -936,6 +1012,12 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-pretty-compact@4.0.0: + resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==} + + kdbush@4.0.2: + resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -981,24 +1063,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -1036,6 +1122,10 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + maplibre-gl@5.19.0: + resolution: {integrity: sha512-REhYUN8gNP3HlcIZS6QU2uy8iovl31cXsrNDkCcqWSQbCkcpdYLczqDz5PVIwNH42UQNyvukjes/RoHPDrOUmQ==} + engines: {node: '>=16.14.0', npm: '>=8.1.0'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1061,6 +1151,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1099,6 +1192,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + pbf@4.0.1: + resolution: {integrity: sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==} + hasBin: true + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1138,6 +1235,9 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + potpack@2.1.0: + resolution: {integrity: sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -1149,10 +1249,16 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + quickselect@3.0.0: + resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -1169,6 +1275,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -1177,6 +1286,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -1220,6 +1332,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supercluster@8.0.1: + resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1241,6 +1356,12 @@ packages: svelte: optional: true + svelte-maplibre-gl@1.0.3: + resolution: {integrity: sha512-pGZMLN5EcJoe6lREyaY2lsbkvrnKjIGHJRM2ijN+TUDeJbV9oecjBxbDXQZd8b5X4JJztSG915L731dFdhhSwA==} + peerDependencies: + maplibre-gl: ^5.0.0 || ^4.0.0 + svelte: '>=5.0.0' + svelte@5.49.1: resolution: {integrity: sha512-jj95WnbKbXsXXngYj28a4zx8jeZx50CN/J4r0CEeax2pbfdsETv/J1K8V9Hbu3DCXnpHz5qAikICuxEooi7eNQ==} engines: {node: '>=18'} @@ -1256,6 +1377,9 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyqueue@3.0.0: + resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==} + ts-api-utils@2.4.0: resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} @@ -1543,6 +1667,53 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@mapbox/geojson-rewind@0.5.2': + dependencies: + get-stream: 6.0.1 + minimist: 1.2.8 + + '@mapbox/jsonlint-lines-primitives@2.0.2': {} + + '@mapbox/point-geometry@1.1.0': {} + + '@mapbox/tiny-sdf@2.0.7': {} + + '@mapbox/unitbezier@0.0.1': {} + + '@mapbox/vector-tile@2.0.4': + dependencies: + '@mapbox/point-geometry': 1.1.0 + '@types/geojson': 7946.0.16 + pbf: 4.0.1 + + '@mapbox/whoots-js@3.1.0': {} + + '@maplibre/geojson-vt@5.0.4': {} + + '@maplibre/maplibre-gl-style-spec@24.6.0': + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 4.0.0 + minimist: 1.2.8 + quickselect: 3.0.0 + rw: 1.3.3 + tinyqueue: 3.0.0 + + '@maplibre/mlt@1.1.6': + dependencies: + '@mapbox/point-geometry': 1.1.0 + + '@maplibre/vt-pbf@4.3.0': + dependencies: + '@mapbox/point-geometry': 1.1.0 + '@mapbox/vector-tile': 2.0.4 + '@maplibre/geojson-vt': 5.0.4 + '@types/geojson': 7946.0.16 + '@types/supercluster': 7.1.3 + pbf: 4.0.1 + supercluster: 8.0.1 + '@rollup/rollup-android-arm-eabi@4.57.1': optional: true @@ -1721,6 +1892,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/json-schema@7.0.15': {} '@types/node@24.10.9': @@ -1731,6 +1904,10 @@ snapshots: dependencies: '@types/node': 24.10.9 + '@types/supercluster@7.1.3': + dependencies: + '@types/geojson': 7946.0.16 + '@types/ws@8.18.1': dependencies: '@types/node': 24.10.9 @@ -1937,6 +2114,8 @@ snapshots: devalue@5.6.2: {} + earcut@3.0.2: {} + enhanced-resolve@5.18.4: dependencies: graceful-fs: 4.2.11 @@ -2103,6 +2282,10 @@ snapshots: fsevents@2.3.3: optional: true + get-stream@6.0.1: {} + + gl-matrix@3.4.4: {} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -2162,6 +2345,10 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-pretty-compact@4.0.0: {} + + kdbush@4.0.2: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -2238,6 +2425,31 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + maplibre-gl@5.19.0: + dependencies: + '@mapbox/geojson-rewind': 0.5.2 + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/point-geometry': 1.1.0 + '@mapbox/tiny-sdf': 2.0.7 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 2.0.4 + '@mapbox/whoots-js': 3.1.0 + '@maplibre/geojson-vt': 5.0.4 + '@maplibre/maplibre-gl-style-spec': 24.6.0 + '@maplibre/mlt': 1.1.6 + '@maplibre/vt-pbf': 4.3.0 + '@types/geojson': 7946.0.16 + '@types/supercluster': 7.1.3 + earcut: 3.0.2 + gl-matrix: 3.4.4 + kdbush: 4.0.2 + murmurhash-js: 1.0.0 + pbf: 4.0.1 + potpack: 2.1.0 + quickselect: 3.0.0 + supercluster: 8.0.1 + tinyqueue: 3.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -2283,6 +2495,8 @@ snapshots: ms@2.1.3: {} + murmurhash-js@1.0.0: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -2321,6 +2535,10 @@ snapshots: path-key@3.1.1: {} + pbf@4.0.1: + dependencies: + resolve-protobuf-schema: 2.1.0 + picocolors@1.1.1: {} picomatch@4.0.3: {} @@ -2351,14 +2569,20 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + potpack@2.1.0: {} + prelude-ls@1.2.1: {} process-nextick-args@2.0.1: {} process@0.11.10: {} + protocol-buffers-schema@3.6.0: {} + punycode@2.3.1: {} + quickselect@3.0.0: {} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -2377,6 +2601,10 @@ snapshots: resolve-from@4.0.0: {} + resolve-protobuf-schema@2.1.0: + dependencies: + protocol-buffers-schema: 3.6.0 + rfdc@1.4.1: {} rollup@4.57.1: @@ -2410,6 +2638,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 + rw@1.3.3: {} + sade@1.8.1: dependencies: mri: 1.2.0 @@ -2441,6 +2671,10 @@ snapshots: strip-json-comments@3.1.1: {} + supercluster@8.0.1: + dependencies: + kdbush: 4.0.2 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -2468,6 +2702,11 @@ snapshots: optionalDependencies: svelte: 5.49.1 + svelte-maplibre-gl@1.0.3(maplibre-gl@5.19.0)(svelte@5.49.1): + dependencies: + maplibre-gl: 5.19.0 + svelte: 5.49.1 + svelte@5.49.1: dependencies: '@jridgewell/remapping': 2.3.5 @@ -2495,6 +2734,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyqueue@3.0.0: {} + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 9517d80..0df97f1 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -1,28 +1,53 @@ -
-
- {#each state.keys() as topic (topic)} -
{topic}: {state.get(topic)}
+
+
+ {#each Object.entries(getDataByPacket($mqttData)) as [packetName, measurements] (packetName)} + {@const packetMeasurements = measurements as Record} +
+

{packetName}

+ {#each Object.entries(packetMeasurements) as [measurementName, measurementValue] (measurementName)} +
{measurementName}: {JSON.stringify(measurementValue)}
+ {/each} +
{/each}
+ + + +
diff --git a/ui/src/stores.ts b/ui/src/stores.ts new file mode 100644 index 0000000..b35d128 --- /dev/null +++ b/ui/src/stores.ts @@ -0,0 +1,85 @@ +import mqtt from "mqtt"; +import { writable } from "svelte/store"; +import type { Writable } from "svelte/store"; + +export const mqttData: Writable> = writable(new Map()); + +let client: mqtt.MqttClient | null = null; + +export function connectMqtt(brokerUrl: string = "ws://localhost:1880") { + if (client) return; + + client = mqtt.connect(brokerUrl); + + client.on("connect", async () => { + console.log("MQTT connected, subscribing to gsw topic"); + await client!.subscribeAsync("gsw/#"); + }); + + client.on("message", (topic, body) => { + try { + const value = JSON.parse(body.toString()); + mqttData.update(state => { + state.set(topic, value); + return state; + }); + } catch (e) { + console.error(`Failed to parse message from ${topic}:`, e); + } + }); + + client.on("error", (error) => { + console.error("MQTT error:", error); + }); +} + +export function disconnectMqtt() { + if (client) { + client.end(true, () => { + console.log("MQTT client closed"); + }); + client = null; + } +} + +export type ParsedTopic = { + prefix: string; + measurement: string; +}; + +export type PacketData = Record; + +export function parseTopic(topic: string): ParsedTopic | null { + const parts = topic.split("/"); + if (parts.length < 2) { + return null; + } + + const [prefix, measurement] = parts; + if (!prefix || !measurement) { + return null; + } + + return { + prefix, + measurement, + }; +} + +export function getDataByPacket(mqttMap: Map): PacketData { + const grouped: PacketData = {}; + + mqttMap.forEach((value, topic) => { + const parsed = parseTopic(topic); + if (!parsed) { + return; + } + + if (!grouped[parsed.prefix]) { + grouped[parsed.prefix] = {}; + } + grouped[parsed.measurement] = value; + }); + + return grouped; +} diff --git a/ui/src/style.aliflux.json b/ui/src/style.aliflux.json new file mode 100644 index 0000000..d534c02 --- /dev/null +++ b/ui/src/style.aliflux.json @@ -0,0 +1,40 @@ +{ + "version": 8, + "name": "Aliflux Offline", + "metadata": {}, + "sources": { + "aliflux": { + "type": "raster", + "tiles": [ + "/aliflux/{z}/{x}/{y}.png" + ], + "tileSize": 256, + "minzoom": 1, + "maxzoom": 6, + "bounds": [ + -165.42133467816151, + -82.63542205486746, + 142.2508008323103, + 84.94825393909099 + ], + "attribution": "EliteMapper by Visor Dynamics" + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "#f6f2ea" + } + }, + { + "id": "aliflux-raster", + "type": "raster", + "source": "aliflux", + "paint": { + "raster-opacity": 1 + } + } + ] +} diff --git a/ui/src/style.json b/ui/src/style.json new file mode 100644 index 0000000..ae87e2e --- /dev/null +++ b/ui/src/style.json @@ -0,0 +1,5896 @@ +{ + "version": 8, + "name": "Voyager", + "metadata": {}, + "sources": { + "carto": { + "type": "vector", + "url": "https://tiles.basemaps.cartocdn.com/vector/carto.streets/v1/tiles.json" + }, + "aliflux": { + "type": "raster" + } + }, + "sprite": "https://tiles.basemaps.cartocdn.com/gl/voyager-gl-style/sprite", + "glyphs": "https://tiles.basemaps.cartocdn.com/fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": { + "visibility": "visible" + }, + "paint": { + "background-color": "#fbf8f3", + "background-opacity": 1 + } + }, + { + "id": "landcover", + "type": "fill", + "source": "carto", + "source-layer": "landcover", + "filter": [ + "any", + [ + "==", + "class", + "wood" + ], + [ + "==", + "class", + "grass" + ], + [ + "==", + "subclass", + "recreation_ground" + ] + ], + "paint": { + "fill-color": { + "stops": [ + [ + 8, + "rgba(197, 225, 178, 0.2)" + ], + [ + 9, + "rgba(197, 225, 178, 0.25)" + ], + [ + 11, + "rgba(197, 225, 178, 0.35)" + ], + [ + 13, + "rgba(197, 225, 178, 0.4)" + ], + [ + 15, + "#e0ecd3" + ] + ] + }, + "fill-opacity": 1 + } + }, + { + "id": "park_national_park", + "type": "fill", + "source": "carto", + "source-layer": "park", + "minzoom": 9, + "filter": [ + "all", + [ + "==", + "class", + "national_park" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": { + "stops": [ + [ + 8, + "rgba(197, 225, 178, 0.2)" + ], + [ + 9, + "rgba(197, 225, 178, 0.25)" + ], + [ + 11, + "rgba(197, 225, 178, 0.35)" + ], + [ + 13, + "rgba(197, 225, 178, 0.4)" + ], + [ + 15, + "#e0ecd3" + ] + ] + }, + "fill-opacity": 1, + "fill-translate-anchor": "map" + } + }, + { + "id": "park_nature_reserve", + "type": "fill", + "source": "carto", + "source-layer": "park", + "minzoom": 0, + "filter": [ + "all", + [ + "==", + "class", + "nature_reserve" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": { + "stops": [ + [ + 8, + "rgba(197, 225, 178, 0.2)" + ], + [ + 9, + "rgba(197, 225, 178, 0.25)" + ], + [ + 11, + "rgba(197, 225, 178, 0.35)" + ], + [ + 13, + "rgba(197, 225, 178, 0.4)" + ], + [ + 15, + "#e0ecd3" + ] + ] + }, + "fill-antialias": true, + "fill-opacity": { + "stops": [ + [ + 6, + 0.7 + ], + [ + 9, + 0.9 + ] + ] + } + } + }, + { + "id": "landuse_residential", + "type": "fill", + "source": "carto", + "source-layer": "landuse", + "minzoom": 6, + "filter": [ + "any", + [ + "==", + "class", + "residential" + ] + ], + "paint": { + "fill-color": { + "stops": [ + [ + 5, + "rgba(243, 234, 220, 0.5)" + ], + [ + 8, + "rgba(243, 234, 220, 0.45)" + ], + [ + 9, + "rgba(243, 234, 220, 0.4)" + ], + [ + 11, + "rgba(243, 234, 220, 0.35)" + ], + [ + 13, + "rgba(243, 234, 220, 0.3)" + ], + [ + 15, + "rgba(243, 234, 220, 0.25)" + ], + [ + 16, + "rgba(243, 234, 220, 0.15)" + ] + ] + }, + "fill-opacity": { + "stops": [ + [ + 6, + 0.6 + ], + [ + 9, + 1 + ] + ] + } + } + }, + { + "id": "landuse", + "type": "fill", + "source": "carto", + "source-layer": "landuse", + "filter": [ + "any", + [ + "==", + "class", + "cemetery" + ], + [ + "==", + "class", + "stadium" + ] + ], + "paint": { + "fill-color": { + "stops": [ + [ + 8, + "rgba(197, 225, 178, 0.2)" + ], + [ + 9, + "rgba(197, 225, 178, 0.25)" + ], + [ + 11, + "rgba(197, 225, 178, 0.35)" + ], + [ + 13, + "rgba(197, 225, 178, 0.4)" + ], + [ + 15, + "#e0ecd3" + ] + ] + } + } + }, + { + "id": "waterway", + "type": "line", + "source": "carto", + "source-layer": "waterway", + "paint": { + "line-color": "#cce7ea", + "line-width": { + "stops": [ + [ + 8, + 0.5 + ], + [ + 9, + 1 + ], + [ + 15, + 2 + ], + [ + 16, + 3 + ] + ] + } + } + }, + { + "id": "boundary_county", + "type": "line", + "source": "carto", + "source-layer": "boundary", + "minzoom": 9, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "admin_level", + 6 + ], + [ + "==", + "maritime", + 0 + ] + ], + "paint": { + "line-color": { + "stops": [ + [ + 4, + "#d4d5d6" + ], + [ + 5, + "#d4d5d6" + ], + [ + 6, + "#e1c5c7" + ] + ] + }, + "line-width": { + "stops": [ + [ + 4, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-dasharray": { + "stops": [ + [ + 6, + [ + 1 + ] + ], + [ + 7, + [ + 2, + 2 + ] + ] + ] + } + } + }, + { + "id": "boundary_state", + "type": "line", + "source": "carto", + "source-layer": "boundary", + "minzoom": 4, + "filter": [ + "all", + [ + "==", + "admin_level", + 4 + ], + [ + "==", + "maritime", + 0 + ] + ], + "paint": { + "line-color": { + "stops": [ + [ + 4, + "#d4d5d6" + ], + [ + 5, + "#d4d5d6" + ], + [ + 6, + "#e1c5c7" + ] + ] + }, + "line-width": { + "stops": [ + [ + 4, + 0.5 + ], + [ + 7, + 1 + ], + [ + 8, + 1 + ], + [ + 9, + 1.2 + ] + ] + }, + "line-dasharray": { + "stops": [ + [ + 6, + [ + 1 + ] + ], + [ + 7, + [ + 2, + 2 + ] + ] + ] + } + } + }, + { + "id": "water", + "type": "fill", + "source": "carto", + "source-layer": "water", + "minzoom": 0, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#b0d0d6", + "fill-antialias": true, + "fill-translate-anchor": "map", + "fill-opacity": 1 + } + }, + { + "id": "water_shadow", + "type": "fill", + "source": "carto", + "source-layer": "water", + "minzoom": 0, + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "rgba(203, 225, 228, 1)", + "fill-antialias": true, + "fill-translate-anchor": "map", + "fill-opacity": 1, + "fill-translate": { + "stops": [ + [ + 0, + [ + 0, + 2 + ] + ], + [ + 6, + [ + 0, + 1 + ] + ], + [ + 14, + [ + 0, + 1 + ] + ], + [ + 17, + [ + 0, + 2 + ] + ] + ] + } + } + }, + { + "id": "aeroway-runway", + "type": "line", + "source": "carto", + "source-layer": "aeroway", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "class", + "runway" + ] + ], + "layout": { + "line-cap": "square" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ] + ] + }, + "line-color": "#e8e8e8" + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "source": "carto", + "source-layer": "aeroway", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "class", + "taxiway" + ] + ], + "paint": { + "line-color": "#e8e8e8", + "line-width": { + "stops": [ + [ + 13, + 0.5 + ], + [ + 14, + 1 + ], + [ + 15, + 2 + ], + [ + 16, + 4 + ] + ] + } + } + }, + { + "id": "waterway_label", + "type": "symbol", + "source": "carto", + "source-layer": "waterway", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "==", + "class", + "river" + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Regular Italic", + "Open Sans Italic", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "symbol-placement": "line", + "symbol-spacing": 300, + "symbol-avoid-edges": false, + "text-size": { + "stops": [ + [ + 9, + 8 + ], + [ + 10, + 9 + ] + ] + }, + "text-padding": 2, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-offset": { + "stops": [ + [ + 6, + [ + 0, + -0.2 + ] + ], + [ + 11, + [ + 0, + -0.4 + ] + ], + [ + 12, + [ + 0, + -0.6 + ] + ] + ] + }, + "text-letter-spacing": 0, + "text-keep-upright": true + }, + "paint": { + "text-color": "#51909c", + "text-halo-color": "#e2eef0", + "text-halo-width": 1 + } + }, + { + "id": "tunnel_service_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 3 + ], + [ + 17, + 6 + ], + [ + 18, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#e6dfcb" + } + }, + { + "id": "tunnel_minor_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 15, + 4 + ], + [ + 16, + 6 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": "#e6dfcb" + } + }, + { + "id": "tunnel_sec_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 5 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#e6dfcb" + } + }, + { + "id": "tunnel_pri_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": "#e6dfcb" + } + }, + { + "id": "tunnel_trunk_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": "#fbdb98" + } + }, + { + "id": "tunnel_mot_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 12, + 4 + ], + [ + 13, + 5 + ], + [ + 14, + 7 + ], + [ + 15, + 9 + ], + [ + 16, + 11 + ], + [ + 17, + 13 + ], + [ + 18, + 22 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": "#fbdb98" + } + }, + { + "id": "tunnel_path", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "path" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 0.5 + ], + [ + 16, + 1 + ], + [ + 18, + 3 + ] + ] + }, + "line-opacity": 1, + "line-color": "#d7d7d7", + "line-dasharray": { + "stops": [ + [ + 15, + [ + 2, + 2 + ] + ], + [ + 18, + [ + 3, + 3 + ] + ] + ] + } + } + }, + { + "id": "tunnel_service_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 2 + ], + [ + 16, + 2 + ], + [ + 17, + 4 + ], + [ + 18, + 6 + ] + ] + }, + "line-opacity": 1, + "line-color": "#f0eee7" + } + }, + { + "id": "tunnel_minor_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 3 + ], + [ + 16, + 4 + ], + [ + 17, + 8 + ], + [ + 18, + 12 + ] + ] + }, + "line-opacity": 1, + "line-color": "rgba(238, 238, 238, 1)" + } + }, + { + "id": "tunnel_sec_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 2 + ], + [ + 13, + 2 + ], + [ + 14, + 3 + ], + [ + 15, + 4 + ], + [ + 16, + 6 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": "#f0eee7" + } + }, + { + "id": "tunnel_pri_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#f0eee7" + } + }, + { + "id": "tunnel_trunk_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#f0eee7" + } + }, + { + "id": "tunnel_mot_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 10, + 1 + ], + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 5 + ], + [ + 15, + 7 + ], + [ + 16, + 9 + ], + [ + 17, + 11 + ], + [ + 18, + 20 + ] + ] + }, + "line-opacity": 1, + "line-color": "#f0eee7" + } + }, + { + "id": "tunnel_rail", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "class", + "rail" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "visibility": "visible", + "line-join": "round" + }, + "paint": { + "line-color": "#dddddd", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 14, + 1 + ], + [ + 15, + 1 + ], + [ + 16, + 3 + ], + [ + 21, + 7 + ] + ] + }, + "line-opacity": 0.5 + } + }, + { + "id": "tunnel_rail_dash", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "class", + "rail" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "layout": { + "visibility": "visible", + "line-join": "round" + }, + "paint": { + "line-color": "#ffffff", + "line-width": { + "base": 1.3, + "stops": [ + [ + 15, + 0.5 + ], + [ + 16, + 1 + ], + [ + 20, + 5 + ] + ] + }, + "line-dasharray": { + "stops": [ + [ + 15, + [ + 5, + 5 + ] + ], + [ + 16, + [ + 6, + 6 + ] + ] + ] + }, + "line-opacity": 0.5 + } + }, + { + "id": "road_service_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 3 + ], + [ + 17, + 6 + ], + [ + 18, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fdebce" + } + }, + { + "id": "road_minor_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 15, + 3 + ], + [ + 16, + 4.3 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 13, + "#ffffff" + ], + [ + 15.7, + "#ffffff" + ], + [ + 16, + "#fdebce" + ] + ] + } + } + }, + { + "id": "road_pri_case_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 15, + 5 + ], + [ + 16, + 8 + ], + [ + 17, + 10 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": "#ffeabb" + } + }, + { + "id": "road_trunk_case_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 15, + 5 + ], + [ + 16, + 8 + ], + [ + 17, + 10 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 12, + "#fbdb98" + ], + [ + 14, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "road_mot_case_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 4 + ], + [ + 15, + 5 + ], + [ + 16, + 8 + ], + [ + 17, + 10 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 12, + "#fbdb98" + ], + [ + 14, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "road_sec_case_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 1.5 + ], + [ + 13, + 3 + ], + [ + 14, + 5 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 11, + "#fffef9" + ], + [ + 12.99, + "#fffef9" + ], + [ + 13, + "#ffedc0" + ] + ] + } + } + }, + { + "id": "road_pri_case_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 7, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 7, + "#ffe7b7" + ], + [ + 12, + "#ffeabb" + ] + ] + } + } + }, + { + "id": "road_trunk_case_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 5, + "#ffe7b7" + ], + [ + 12, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "road_mot_case_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.7 + ], + [ + 8, + 0.8 + ], + [ + 11, + 3 + ], + [ + 12, + 4 + ], + [ + 13, + 5 + ], + [ + 14, + 7 + ], + [ + 15, + 9 + ], + [ + 16, + 11 + ], + [ + 17, + 13 + ], + [ + 18, + 22 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 5, + "#fbdb98" + ], + [ + 12, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "road_path", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "path", + "track" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 0.5 + ], + [ + 16, + 1 + ], + [ + 18, + 3 + ] + ] + }, + "line-opacity": 1, + "line-color": "#d7d7d7", + "line-dasharray": { + "stops": [ + [ + 15, + [ + 2, + 2 + ] + ], + [ + 18, + [ + 3, + 3 + ] + ] + ] + } + } + }, + { + "id": "road_service_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 2 + ], + [ + 16, + 2 + ], + [ + 17, + 4 + ], + [ + 18, + 6 + ] + ] + }, + "line-opacity": 1, + "line-color": "#ffffff" + } + }, + { + "id": "road_minor_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 3 + ], + [ + 16, + 4 + ], + [ + 17, + 8 + ], + [ + 18, + 12 + ] + ] + }, + "line-opacity": 1, + "line-color": "#ffffff" + } + }, + { + "id": "road_pri_fill_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2 + ], + [ + 15, + 3 + ], + [ + 16, + 6 + ], + [ + 17, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fefdd7" + } + }, + { + "id": "road_trunk_fill_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "square", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2 + ], + [ + 15, + 3 + ], + [ + 16, + 6 + ], + [ + 17, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "road_mot_fill_ramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 12, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "ramp", + 1 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 12, + 1 + ], + [ + 13, + 1.5 + ], + [ + 14, + 2 + ], + [ + 15, + 3 + ], + [ + 16, + 6 + ], + [ + 17, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "road_sec_fill_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 2 + ], + [ + 13, + 2 + ], + [ + 14, + 3 + ], + [ + 15, + 4 + ], + [ + 16, + 6 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fefdd7" + } + }, + { + "id": "road_pri_fill_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 10, + 0.3 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fefdd7" + } + }, + { + "id": "road_trunk_fill_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "road_mot_fill_noramp", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "!has", + "brunnel" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 10, + 1 + ], + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 5 + ], + [ + 15, + 7 + ], + [ + 16, + 9 + ], + [ + 17, + 11 + ], + [ + 18, + 20 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "rail", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "class", + "rail" + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "layout": { + "visibility": "visible", + "line-join": "round" + }, + "paint": { + "line-color": "#dddddd", + "line-width": { + "base": 1.3, + "stops": [ + [ + 13, + 0.5 + ], + [ + 14, + 1 + ], + [ + 15, + 1 + ], + [ + 16, + 3 + ], + [ + 21, + 7 + ] + ] + } + } + }, + { + "id": "rail_dash", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "class", + "rail" + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "layout": { + "visibility": "visible", + "line-join": "round" + }, + "paint": { + "line-color": "#ffffff", + "line-width": { + "base": 1.3, + "stops": [ + [ + 15, + 0.5 + ], + [ + 16, + 1 + ], + [ + 20, + 5 + ] + ] + }, + "line-dasharray": { + "stops": [ + [ + 15, + [ + 5, + 5 + ] + ], + [ + 16, + [ + 6, + 6 + ] + ] + ] + } + } + }, + { + "id": "bridge_service_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 3 + ], + [ + 17, + 6 + ], + [ + 18, + 8 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fdebce" + } + }, + { + "id": "bridge_minor_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 15, + 3 + ], + [ + 16, + 4.3 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 13, + "#ffffff" + ], + [ + 15.7, + "#ffffff" + ], + [ + 16, + "#fdebce" + ] + ] + } + } + }, + { + "id": "bridge_sec_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 0.5 + ], + [ + 12, + 1.5 + ], + [ + 13, + 3 + ], + [ + 14, + 5 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": { + "stops": [ + [ + 11, + "#fffef9" + ], + [ + 12.99, + "#fffef9" + ], + [ + 13, + "#ffedc0" + ] + ] + } + } + }, + { + "id": "bridge_pri_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 8, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 8, + "#ffe7b7" + ], + [ + 12, + "#ffeabb" + ] + ] + } + } + }, + { + "id": "bridge_trunk_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 13, + 4 + ], + [ + 14, + 6 + ], + [ + 15, + 8 + ], + [ + 16, + 10 + ], + [ + 17, + 14 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 5, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 5, + "#fbdb98" + ], + [ + 12, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "bridge_mot_case", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 5, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 0.8 + ], + [ + 8, + 1 + ], + [ + 11, + 3 + ], + [ + 12, + 4 + ], + [ + 13, + 5 + ], + [ + 14, + 7 + ], + [ + 15, + 9 + ], + [ + 16, + 11 + ], + [ + 17, + 13 + ], + [ + 18, + 22 + ] + ] + }, + "line-opacity": { + "stops": [ + [ + 6, + 0.5 + ], + [ + 7, + 1 + ] + ] + }, + "line-color": { + "stops": [ + [ + 5, + "#fbdb98" + ], + [ + 10, + "#fbdb98" + ] + ] + } + } + }, + { + "id": "bridge_path", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "path" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 0.5 + ], + [ + 16, + 1 + ], + [ + 18, + 3 + ] + ] + }, + "line-opacity": 1, + "line-color": "#d7d7d7", + "line-dasharray": { + "stops": [ + [ + 15, + [ + 2, + 2 + ] + ], + [ + 18, + [ + 3, + 3 + ] + ] + ] + } + } + }, + { + "id": "bridge_service_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "service" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 2 + ], + [ + 16, + 2 + ], + [ + 17, + 4 + ], + [ + 18, + 6 + ] + ] + }, + "line-opacity": 1, + "line-color": "#ffffff" + } + }, + { + "id": "bridge_minor_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 15, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "minor" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 15, + 3 + ], + [ + 16, + 4 + ], + [ + 17, + 8 + ], + [ + 18, + 12 + ] + ] + }, + "line-opacity": 1, + "line-color": "#ffffff" + } + }, + { + "id": "bridge_sec_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 13, + "maxzoom": 24, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 2 + ], + [ + 13, + 2 + ], + [ + 14, + 3 + ], + [ + 15, + 4 + ], + [ + 16, + 6 + ], + [ + 17, + 10 + ], + [ + 18, + 14 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fefdd7" + } + }, + { + "id": "bridge_pri_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#fefdd7" + } + }, + { + "id": "bridge_trunk_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 11, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-width": { + "stops": [ + [ + 11, + 1 + ], + [ + 13, + 2 + ], + [ + 14, + 4 + ], + [ + 15, + 6 + ], + [ + 16, + 8 + ], + [ + 17, + 12 + ], + [ + 18, + 16 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "bridge_mot_fill", + "type": "line", + "source": "carto", + "source-layer": "transportation", + "minzoom": 10, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "!=", + "ramp", + 1 + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "stops": [ + [ + 10, + 1 + ], + [ + 12, + 2 + ], + [ + 13, + 3 + ], + [ + 14, + 5 + ], + [ + 15, + 7 + ], + [ + 16, + 9 + ], + [ + 17, + 11 + ], + [ + 18, + 20 + ] + ] + }, + "line-opacity": 1, + "line-color": "#FFE9A5" + } + }, + { + "id": "building", + "type": "fill", + "source": "carto", + "source-layer": "building", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15.5, + "#e4dcd0" + ], + [ + 16, + "#e4dcd0" + ] + ] + }, + "fill-antialias": true + } + }, + { + "id": "building-top", + "type": "fill", + "source": "carto", + "source-layer": "building", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-translate": { + "base": 1, + "stops": [ + [ + 14, + [ + 0, + 0 + ] + ], + [ + 16, + [ + -2, + -2 + ] + ] + ] + }, + "fill-outline-color": "#e9d8be", + "fill-color": "#f3eadc", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 16, + 1 + ] + ] + } + } + }, + { + "id": "boundary_country_outline", + "type": "line", + "source": "carto", + "source-layer": "boundary", + "minzoom": 6, + "maxzoom": 24, + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#f3efed", + "line-opacity": 0.5, + "line-width": 8, + "line-offset": 0 + } + }, + { + "id": "boundary_country_inner", + "type": "line", + "source": "carto", + "source-layer": "boundary", + "minzoom": 0, + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": { + "stops": [ + [ + 4, + "#ead5d7" + ], + [ + 5, + "#ebd6d8" + ], + [ + 6, + "#ebd6d8" + ] + ] + }, + "line-opacity": 1, + "line-width": { + "stops": [ + [ + 3, + 1 + ], + [ + 6, + 1.5 + ] + ] + }, + "line-offset": 0 + } + }, + { + "id": "watername_ocean", + "type": "symbol", + "source": "carto", + "source-layer": "water_name", + "minzoom": 0, + "maxzoom": 5, + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "ocean" + ] + ], + "layout": { + "text-field": "{name}", + "symbol-placement": "point", + "text-size": { + "stops": [ + [ + 0, + 13 + ], + [ + 2, + 14 + ], + [ + 4, + 18 + ] + ] + }, + "text-font": [ + "Montserrat Medium Italic", + "Open Sans Italic", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-line-height": 1.2, + "text-padding": 2, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-max-width": 6, + "text-letter-spacing": 0.1 + }, + "paint": { + "text-color": "#ffffff", + "text-halo-color": "#98c2ca", + "text-halo-width": 1, + "text-halo-blur": 0 + } + }, + { + "id": "watername_sea", + "type": "symbol", + "source": "carto", + "source-layer": "water_name", + "minzoom": 5, + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "sea" + ] + ], + "layout": { + "text-field": "{name}", + "symbol-placement": "point", + "text-size": 12, + "text-font": [ + "Montserrat Medium Italic", + "Open Sans Italic", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-line-height": 1.2, + "text-padding": 2, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-max-width": 6, + "text-letter-spacing": 0.1 + }, + "paint": { + "text-color": "#ffffff", + "text-halo-color": "#98c2ca", + "text-halo-width": 1, + "text-halo-blur": 0 + } + }, + { + "id": "watername_lake", + "type": "symbol", + "source": "carto", + "source-layer": "water_name", + "minzoom": 4, + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "lake" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "symbol-placement": "point", + "text-size": { + "stops": [ + [ + 13, + 9 + ], + [ + 14, + 10 + ], + [ + 15, + 11 + ], + [ + 16, + 12 + ], + [ + 17, + 13 + ] + ] + }, + "text-font": [ + "Montserrat Regular Italic", + "Open Sans Italic", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-line-height": 1.2, + "text-padding": 2, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto" + }, + "paint": { + "text-color": "#51909c", + "text-halo-color": "#e2eef0", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "watername_lake_line", + "type": "symbol", + "source": "carto", + "source-layer": "water_name", + "filter": [ + "all", + [ + "has", + "name" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "symbol-placement": "line", + "text-size": { + "stops": [ + [ + 13, + 9 + ], + [ + 14, + 10 + ], + [ + 15, + 11 + ], + [ + 16, + 12 + ], + [ + 17, + 13 + ] + ] + }, + "text-font": [ + "Montserrat Regular Italic", + "Open Sans Italic", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "symbol-spacing": 350, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-line-height": 1.2 + }, + "paint": { + "text-color": "#51909c", + "text-halo-color": "#e2eef0", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "place_hamlet", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 12, + "maxzoom": 16, + "filter": [ + "any", + [ + "==", + "class", + "neighbourhood" + ], + [ + "==", + "class", + "hamlet" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 14, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 13, + 8 + ], + [ + 14, + 10 + ], + [ + 16, + 11 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": { + "stops": [ + [ + 12, + "none" + ], + [ + 14, + "uppercase" + ] + ] + } + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_suburbs", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 12, + "maxzoom": 16, + "filter": [ + "all", + [ + "==", + "class", + "suburb" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 12, + 9 + ], + [ + 13, + 10 + ], + [ + 14, + 11 + ], + [ + 15, + 12 + ], + [ + 16, + 13 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": { + "stops": [ + [ + 8, + "none" + ], + [ + 12, + "uppercase" + ] + ] + } + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_villages", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 10, + "maxzoom": 16, + "filter": [ + "all", + [ + "==", + "class", + "village" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 10, + 9 + ], + [ + 12, + 10 + ], + [ + 13, + 11 + ], + [ + 14, + 12 + ], + [ + 16, + 13 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": "none" + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_town", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 8, + "maxzoom": 14, + "filter": [ + "all", + [ + "==", + "class", + "town" + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 8, + 10 + ], + [ + 9, + 10 + ], + [ + 10, + 11 + ], + [ + 13, + 14 + ], + [ + 14, + 15 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": "none" + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_country_2", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 3, + "maxzoom": 10, + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + ">=", + "rank", + 3 + ], + [ + "has", + "iso_a2" + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 3, + 10 + ], + [ + 5, + 11 + ], + [ + 6, + 12 + ], + [ + 7, + 13 + ], + [ + 8, + 14 + ] + ] + }, + "text-transform": "uppercase" + }, + "paint": { + "text-color": { + "stops": [ + [ + 3, + "#6b7d91" + ], + [ + 5, + "#8894a3" + ], + [ + 6, + "#a3abb5" + ] + ] + }, + "text-halo-color": "#fbf8f3", + "text-halo-width": 1 + } + }, + { + "id": "place_country_1", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 2, + "maxzoom": 7, + "filter": [ + "all", + [ + "==", + "class", + "country" + ], + [ + "<=", + "rank", + 2 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 3, + 11 + ], + [ + 4, + 12 + ], + [ + 5, + 13 + ], + [ + 6, + 14 + ] + ] + }, + "text-transform": "uppercase", + "text-max-width": { + "stops": [ + [ + 2, + 6 + ], + [ + 3, + 6 + ], + [ + 4, + 9 + ], + [ + 5, + 12 + ] + ] + } + }, + "paint": { + "text-color": { + "stops": [ + [ + 3, + "#6b7d91" + ], + [ + 5, + "#8894a3" + ], + [ + 6, + "#a3abb5" + ] + ] + }, + "text-halo-color": "#fbf8f3", + "text-halo-width": 1 + } + }, + { + "id": "place_state", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 5, + "maxzoom": 10, + "filter": [ + "all", + [ + "==", + "class", + "state" + ], + [ + "<=", + "rank", + 4 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 5, + 12 + ], + [ + 7, + 14 + ] + ] + }, + "text-transform": "uppercase", + "text-max-width": 9 + }, + "paint": { + "text-color": "#7c8a9b", + "text-halo-color": "#fbf8f3", + "text-halo-width": 0 + } + }, + { + "id": "place_continent", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 0, + "maxzoom": 2, + "filter": [ + "all", + [ + "==", + "class", + "continent" + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-transform": "uppercase", + "text-size": 14, + "text-letter-spacing": 0.1, + "text-max-width": 9, + "text-justify": "center", + "text-keep-upright": false + }, + "paint": { + "text-color": "#405c78", + "text-halo-color": "#fbf8f3", + "text-halo-width": 1 + } + }, + { + "id": "place_city_r6", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 8, + "maxzoom": 15, + "filter": [ + "all", + [ + "==", + "class", + "city" + ], + [ + ">=", + "rank", + 6 + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 8, + 12 + ], + [ + 9, + 13 + ], + [ + 10, + 14 + ], + [ + 13, + 17 + ], + [ + 14, + 20 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_city_r5", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 8, + "maxzoom": 15, + "filter": [ + "all", + [ + "==", + "class", + "city" + ], + [ + ">=", + "rank", + 0 + ], + [ + "<=", + "rank", + 5 + ] + ], + "layout": { + "text-field": { + "stops": [ + [ + 8, + "{name_en}" + ], + [ + 13, + "{name}" + ] + ] + }, + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 8, + 14 + ], + [ + 10, + 16 + ], + [ + 13, + 19 + ], + [ + 14, + 22 + ] + ] + }, + "icon-image": "", + "icon-offset": [ + 16, + 0 + ], + "text-anchor": "center", + "icon-size": 1, + "text-max-width": 10, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_city_dot_r7", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 6, + "maxzoom": 7, + "filter": [ + "all", + [ + "==", + "class", + "city" + ], + [ + "<=", + "rank", + 7 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 12, + "icon-image": "circle-11", + "icon-offset": [ + 16, + 5 + ], + "text-anchor": "right", + "icon-size": 0.4, + "text-max-width": 8, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ] + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_city_dot_r4", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 5, + "maxzoom": 7, + "filter": [ + "all", + [ + "==", + "class", + "city" + ], + [ + "<=", + "rank", + 4 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 12, + "icon-image": "circle-11", + "icon-offset": [ + 16, + 5 + ], + "text-anchor": "right", + "icon-size": 0.4, + "text-max-width": 8, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ] + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_city_dot_r2", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 4, + "maxzoom": 7, + "filter": [ + "all", + [ + "==", + "class", + "city" + ], + [ + "<=", + "rank", + 2 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 12, + "icon-image": "circle-11", + "icon-offset": [ + 16, + 5 + ], + "text-anchor": "right", + "icon-size": 0.4, + "text-max-width": 8, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ] + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_city_dot_z7", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 7, + "maxzoom": 8, + "filter": [ + "all", + [ + "!has", + "capital" + ], + [ + "!in", + "class", + "country", + "state" + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 12, + "icon-image": "circle-11", + "icon-offset": [ + 16, + 5 + ], + "text-anchor": "right", + "icon-size": 0.4, + "text-max-width": 8, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ] + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "place_capital_dot_z7", + "type": "symbol", + "source": "carto", + "source-layer": "place", + "minzoom": 7, + "maxzoom": 8, + "filter": [ + "all", + [ + ">", + "capital", + 0 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 12, + "icon-image": "circle-11", + "icon-offset": [ + 16, + 5 + ], + "text-anchor": "right", + "icon-size": 0.4, + "text-max-width": 8, + "text-keep-upright": true, + "text-offset": [ + 0.2, + 0.2 + ], + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#405c78", + "icon-color": "#405c78", + "icon-translate-anchor": "map", + "text-halo-color": "#f2f5f8", + "text-halo-width": 1 + } + }, + { + "id": "poi_stadium", + "type": "symbol", + "source": "carto", + "source-layer": "poi", + "minzoom": 15, + "filter": [ + "all", + [ + "in", + "class", + "stadium", + "cemetery", + "attraction" + ], + [ + "<=", + "rank", + 3 + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 15, + 8 + ], + [ + 17, + 9 + ], + [ + 18, + 10 + ] + ] + }, + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#666666", + "text-halo-color": "rgba(255,255,255,0.15)", + "text-halo-width": 1 + } + }, + { + "id": "poi_park", + "type": "symbol", + "source": "carto", + "source-layer": "poi", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "class", + "park" + ] + ], + "layout": { + "text-field": "{name}", + "text-font": [ + "Montserrat Medium", + "Open Sans Bold", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 15, + 8 + ], + [ + 17, + 9 + ], + [ + 18, + 10 + ] + ] + }, + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#666666", + "text-halo-color": "rgba(255,255,255,0.15)", + "text-halo-width": 1 + } + }, + { + "id": "roadname_minor", + "type": "symbol", + "source": "carto", + "source-layer": "transportation_name", + "minzoom": 16, + "filter": [ + "all", + [ + "in", + "class", + "minor", + "service" + ] + ], + "layout": { + "symbol-placement": "line", + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": 9, + "text-field": "{name}", + "symbol-avoid-edges": false, + "symbol-spacing": 200, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-justify": "center" + }, + "paint": { + "text-color": "#87919e", + "text-halo-color": "#fbf8f3", + "text-halo-width": 1 + } + }, + { + "id": "roadname_sec", + "type": "symbol", + "source": "carto", + "source-layer": "transportation_name", + "minzoom": 15, + "filter": [ + "all", + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "layout": { + "symbol-placement": "line", + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 15, + 9 + ], + [ + 16, + 11 + ], + [ + 18, + 12 + ] + ] + }, + "text-field": "{name}", + "symbol-avoid-edges": false, + "symbol-spacing": 200, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-justify": "center" + }, + "paint": { + "text-color": "#87919e", + "text-halo-color": "#fbf8f3", + "text-halo-width": 1 + } + }, + { + "id": "roadname_pri", + "type": "symbol", + "source": "carto", + "source-layer": "transportation_name", + "minzoom": 14, + "filter": [ + "all", + [ + "in", + "class", + "primary" + ] + ], + "layout": { + "symbol-placement": "line", + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 14, + 10 + ], + [ + 15, + 10 + ], + [ + 16, + 11 + ], + [ + 18, + 12 + ] + ] + }, + "text-field": "{name}", + "symbol-avoid-edges": false, + "symbol-spacing": { + "stops": [ + [ + 6, + 200 + ], + [ + 16, + 250 + ] + ] + }, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-justify": "center", + "text-letter-spacing": { + "stops": [ + [ + 14, + 0 + ], + [ + 16, + 0.2 + ] + ] + } + }, + "paint": { + "text-color": "#798493", + "text-halo-color": "#fefde1", + "text-halo-width": 1 + } + }, + { + "id": "roadname_major", + "type": "symbol", + "source": "carto", + "source-layer": "transportation_name", + "minzoom": 13, + "filter": [ + "all", + [ + "in", + "class", + "trunk", + "motorway" + ] + ], + "layout": { + "symbol-placement": "line", + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ], + "text-size": { + "stops": [ + [ + 14, + 10 + ], + [ + 15, + 10 + ], + [ + 16, + 11 + ], + [ + 18, + 12 + ] + ] + }, + "text-field": "{name}", + "symbol-avoid-edges": false, + "symbol-spacing": { + "stops": [ + [ + 6, + 200 + ], + [ + 16, + 250 + ] + ] + }, + "text-pitch-alignment": "auto", + "text-rotation-alignment": "auto", + "text-justify": "center", + "text-letter-spacing": { + "stops": [ + [ + 13, + 0 + ], + [ + 16, + 0.2 + ] + ] + } + }, + "paint": { + "text-color": "#798493", + "text-halo-color": "#fff0c4", + "text-halo-width": 1 + } + }, + { + "id": "housenumber", + "type": "symbol", + "source": "carto", + "source-layer": "housenumber", + "minzoom": 17, + "maxzoom": 24, + "layout": { + "text-field": "{housenumber}", + "text-size": { + "stops": [ + [ + 17, + 9 + ], + [ + 18, + 11 + ] + ] + }, + "text-font": [ + "Montserrat Regular", + "Open Sans Regular", + "Noto Sans Regular", + "HanWangHeiLight Regular", + "NanumBarunGothic Regular" + ] + }, + "paint": { + "text-halo-color": "rgba(255,255,255,0.15)", + "text-color": "#d2b17d", + "text-halo-width": 0.75 + } + } + ], + "id": "voyager", + "owner": "Carto" +} diff --git a/ui/src/types/svelte-maplibre-gl.d.ts b/ui/src/types/svelte-maplibre-gl.d.ts new file mode 100644 index 0000000..3ebb62a --- /dev/null +++ b/ui/src/types/svelte-maplibre-gl.d.ts @@ -0,0 +1,7 @@ +declare module "svelte-maplibre-gl" { + export const MapLibre: any; + export const NavigationControl: any; + export const ScaleControl: any; + export const GlobeControl: any; + export const Marker: any; +} diff --git a/ui/tsconfig.app.json b/ui/tsconfig.app.json index 31c18cf..65e2fbd 100644 --- a/ui/tsconfig.app.json +++ b/ui/tsconfig.app.json @@ -5,6 +5,8 @@ "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", + "moduleResolution": "bundler", + "customConditions": ["svelte"], "types": ["svelte", "vite/client"], "noEmit": true, /** @@ -17,5 +19,5 @@ "checkJs": true, "moduleDetection": "force" }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] } From e944dde01f1c124b8e569445dde30bdccc79068e Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 2 Apr 2026 19:35:07 -0400 Subject: [PATCH 06/12] feat: better zooming --- ui/src/App.svelte | 31 +++++++++++++++++++++++-------- ui/src/stores.ts | 16 +++++++++------- ui/src/style.aliflux.json | 2 +- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 0df97f1..c9a51bb 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -5,6 +5,7 @@ import "maplibre-gl/dist/maplibre-gl.css"; let markerPosition = { lng: -77.67641, lat: 43.08348 }; + let satCount = 0 onMount(() => { connectMqtt(); @@ -17,17 +18,23 @@ // Subscribe to MQTT data changes $: { const data = getDataByPacket($mqttData); - const gnsscoordinates = data.gnsscoordinates as - | { latitude?: number; longitude?: number } - | undefined; - if (gnsscoordinates && typeof gnsscoordinates.latitude === 'number' && typeof gnsscoordinates.longitude === 'number') { - markerPosition = { lng: gnsscoordinates.longitude, lat: gnsscoordinates.latitude }; + const prefix = data.b + if (prefix) { + const gnsscoordinates = prefix.gnsscoordinates as + | { latitude?: number; longitude?: number, sat_count?: number } + | undefined; + if (gnsscoordinates && typeof gnsscoordinates.latitude === 'number' && typeof gnsscoordinates.longitude === 'number') { + markerPosition = { lng: gnsscoordinates.longitude, lat: gnsscoordinates.latitude }; + } + if (gnsscoordinates && typeof gnsscoordinates.sat_count === 'number') { + satCount = gnsscoordinates.sat_count + } } } -
-
+
+
{#each Object.entries(getDataByPacket($mqttData)) as [packetName, measurements] (packetName)} {@const packetMeasurements = measurements as Record}
@@ -37,9 +44,10 @@ {/each}
{/each} +
+
+ Sat: {satCount !== null ? `${satCount}` : "--"} +
+
+ LAT: {markerPosition.lat !== null ? `${markerPosition.lat.toFixed(5)}` : "--.-----"}, + LONG: {markerPosition.lng !== null ? `${markerPosition.lng.toFixed(5)}` : "--.-----"} +
diff --git a/ui/src/stores.ts b/ui/src/stores.ts index b35d128..1c9f3f2 100644 --- a/ui/src/stores.ts +++ b/ui/src/stores.ts @@ -44,24 +44,26 @@ export function disconnectMqtt() { export type ParsedTopic = { prefix: string; + packet: string; measurement: string; }; -export type PacketData = Record; +export type PacketData = Record>; export function parseTopic(topic: string): ParsedTopic | null { const parts = topic.split("/"); - if (parts.length < 2) { + if (parts.length < 3) { return null; } - const [prefix, measurement] = parts; - if (!prefix || !measurement) { + const [prefix, packet, measurement] = parts; + if (!prefix || !packet || !measurement) { return null; } return { prefix, + packet, measurement, }; } @@ -75,10 +77,10 @@ export function getDataByPacket(mqttMap: Map): PacketData { return; } - if (!grouped[parsed.prefix]) { - grouped[parsed.prefix] = {}; + if (!grouped[parsed.packet]) { + grouped[parsed.packet] = {}; } - grouped[parsed.measurement] = value; + grouped[parsed.packet][parsed.measurement] = value; }); return grouped; diff --git a/ui/src/style.aliflux.json b/ui/src/style.aliflux.json index d534c02..63eb5f5 100644 --- a/ui/src/style.aliflux.json +++ b/ui/src/style.aliflux.json @@ -10,7 +10,7 @@ ], "tileSize": 256, "minzoom": 1, - "maxzoom": 6, + "maxzoom": 19, "bounds": [ -165.42133467816151, -82.63542205486746, From 96015390949a7f1b100e1c5607017d289bae6cfd Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 9 Apr 2026 19:24:43 -0400 Subject: [PATCH 07/12] feat: added data boxes for battery, snr, temps, and Gs --- ui/src/App.svelte | 186 ++++++++++++++++++++++++++++++++++++---------- ui/src/stores.ts | 124 +++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+), 39 deletions(-) diff --git a/ui/src/App.svelte b/ui/src/App.svelte index c9a51bb..0e7a804 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -1,68 +1,176 @@
-
- {#each Object.entries(getDataByPacket($mqttData)) as [packetName, measurements] (packetName)} - {@const packetMeasurements = measurements as Record} -
-

{packetName}

- {#each Object.entries(packetMeasurements) as [measurementName, measurementValue] (measurementName)} -
{measurementName}: {JSON.stringify(measurementValue)}
- {/each} -
- {/each} - +
+
+ {#each topLeftMetricStubs as metric (metric.label)} +
+
{metric.label}
+
{metric.value}
+
+ {/each} +
- - - - -
- Sat: {satCount !== null ? `${satCount}` : "--"} + RISK +
+ +
+
+
Altitude
+
+
+
+
+
{altitude !== null ? `${altitude.toFixed(0)}ft` : "--"}
+
-
- LAT: {markerPosition.lat !== null ? `${markerPosition.lat.toFixed(5)}` : "--.-----"}, - LONG: {markerPosition.lng !== null ? `${markerPosition.lng.toFixed(5)}` : "--.-----"} + +
+
+
G Force
+
+
+
+
+
+ {gForce !== null ? `${gForce.toFixed(2)}g` : "--"} +
+
+
+ +
+
+ + + + +
+ SAT: {satCount !== null ? `${satCount}` : "--"} +
+
+
+ LAT: {markerPosition.lat !== null ? `${markerPosition.lat.toFixed(5)}` : "--.-----"}, + LNG: {markerPosition.lng !== null ? `${markerPosition.lng.toFixed(5)}` : "--.-----"} +
diff --git a/ui/src/stores.ts b/ui/src/stores.ts index 1c9f3f2..9aad738 100644 --- a/ui/src/stores.ts +++ b/ui/src/stores.ts @@ -5,6 +5,26 @@ import type { Writable } from "svelte/store"; export const mqttData: Writable> = writable(new Map()); let client: mqtt.MqttClient | null = null; +let sineWaveGeneratorInterval: ReturnType | null = null; + +export type SineWaveGeneratorOptions = { + intervalMs?: number; + baseLat?: number; + baseLng?: number; + channel?: string | number; +}; + +function emitSyntheticMessage(topic: string, value: unknown) { + // Mirror test samples directly into local state so UI updates immediately. + mqttData.update((state) => { + state.set(topic, value); + return state; + }); + + if (client?.connected) { + client.publish(topic, JSON.stringify(value)); + } +} export function connectMqtt(brokerUrl: string = "ws://localhost:1880") { if (client) return; @@ -42,6 +62,62 @@ export function disconnectMqtt() { } } +export function startSineWaveMqttGenerator(options: SineWaveGeneratorOptions = {}) { + if (sineWaveGeneratorInterval) return; + + const intervalMs = options.intervalMs ?? 250; + const baseLat = options.baseLat ?? 43.08348; + const baseLng = options.baseLng ?? -77.67641; + const channel = String(options.channel ?? "1"); + const topicRoot = `gsw/${channel}/`; + const startTime = Date.now(); + + sineWaveGeneratorInterval = setInterval(() => { + const t = (Date.now() - startTime) / 1000; + + const latitude = baseLat + Math.sin(t * 0.3) * 0.02; + const longitude = baseLng + Math.cos(t * 0.25) * 0.02; + const altitude = 9000 + Math.sin(t * 0.5) * 1200; + const satCount = Math.max(0, Math.round(8 + Math.sin(t * 0.4) * 3)); + + const voltBatt = 11.8 + Math.sin(t * 0.35) * 0.6; + const currBatt = 1.5 + Math.sin(t * 0.8) * 0.9; + const snr = 20 + Math.sin(t * 0.6) * 5; + const temperature = 24 + Math.sin(t * 0.22) * 4; + + const accel_x = 9.81 + Math.sin(t + 0.35) + const accel_y = 9.81 + Math.sin(t + 0.35) + const accel_z = 9.81 + Math.sin(t + 0.35) + + emitSyntheticMessage(topicRoot + "gnsscoordinates", { + latitude, + longitude, + altitude, + sat_count: satCount, + }); + emitSyntheticMessage(topicRoot + "powermodule", { + VOLT_BATT: voltBatt, + CURR_BATT: currBatt, + }); + emitSyntheticMessage(topicRoot + "receiverstats", { + snr, + }); + emitSyntheticMessage(topicRoot + "sensormodule", { + temperature, + accel_x, + accel_y, + accel_z, + }); + }, intervalMs); +} + +export function stopSineWaveMqttGenerator() { + if (!sineWaveGeneratorInterval) return; + + clearInterval(sineWaveGeneratorInterval); + sineWaveGeneratorInterval = null; +} + export type ParsedTopic = { prefix: string; packet: string; @@ -85,3 +161,51 @@ export function getDataByPacket(mqttMap: Map): PacketData { return grouped; } + +export function getValueCaseInsensitive(source: Record | undefined, key: string): unknown { + if (!source) return undefined; + + const keyLower = key.toLowerCase(); + for (const [entryKey, entryValue] of Object.entries(source)) { + if (entryKey.toLowerCase() === keyLower) { + return entryValue; + } + } + + return undefined; +} + +export function getObjectCaseInsensitive(source: Record | undefined, key: string): Record | undefined { + const value = getValueCaseInsensitive(source, key); + if (value && typeof value === "object" && !Array.isArray(value)) { + return value as Record; + } + return undefined; +} + +export function getNumberCaseInsensitive(source: Record | undefined, ...keys: string[]): number | null { + for (const key of keys) { + const value = getValueCaseInsensitive(source, key); + if (typeof value === "number") { + return value; + } + } + return null; +} + +export function getChannelPayload( + packetData: Record, + channel?: string | number, +): Record | undefined { + if (channel !== undefined) { + return getObjectCaseInsensitive(packetData, String(channel)); + } + + for (const value of Object.values(packetData)) { + if (value && typeof value === "object" && !Array.isArray(value)) { + return value as Record; + } + } + + return undefined; +} From 8440b6c2211ec3b5fd1f2512c5c915a045ac2e33 Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 16 Apr 2026 19:30:10 -0400 Subject: [PATCH 08/12] feat: added guardians font and url params --- ui/public/Guardians.ttf | Bin 0 -> 8420 bytes ui/public/ritlaunch.png | Bin 0 -> 5117 bytes ui/src/App.svelte | 161 +++++++++++++++++++++++++++++++++------- ui/src/index.css | 12 +++ 4 files changed, 148 insertions(+), 25 deletions(-) create mode 100644 ui/public/Guardians.ttf create mode 100644 ui/public/ritlaunch.png diff --git a/ui/public/Guardians.ttf b/ui/public/Guardians.ttf new file mode 100644 index 0000000000000000000000000000000000000000..43d5a5d03876cccd9d5885f646dcea07f492dda2 GIT binary patch literal 8420 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 literal 0 HcmV?d00001 diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 0e7a804..5a92052 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -1,3 +1,4 @@ + -
-
+
+
{#each topLeftMetricStubs as metric (metric.label)}
-
{metric.label}
-
{metric.value}
+
+
{metric.value} {metric.label}
{/each}
RISK
-
+
+
+ RIT LAUNCH + INITIATIVE +
+ RIT Launch logo +
+ +
Altitude
+
@@ -131,16 +217,20 @@
-
+
G Force
+
@@ -150,27 +240,48 @@
+
+
+ {callSign ? callSign : "------"} +
+
+ +
+
+ Last trans: {secondsSinceLastTransmission !== null ? `${secondsSinceLastTransmission}s` : "------"} +
+
+
- - + + Launch logo + + + Launch logo + +
SAT: {satCount !== null ? `${satCount}` : "--"}
- LAT: {markerPosition.lat !== null ? `${markerPosition.lat.toFixed(5)}` : "--.-----"}, - LNG: {markerPosition.lng !== null ? `${markerPosition.lng.toFixed(5)}` : "--.-----"} + LAT: {rocketPosition.lat !== null ? `${rocketPosition.lat.toFixed(5)}` : "--.-----"}, + LNG: {rocketPosition.lng !== null ? `${rocketPosition.lng.toFixed(5)}` : "--.-----"}
diff --git a/ui/src/index.css b/ui/src/index.css index f1d8c73..d5a38c5 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -1 +1,13 @@ @import "tailwindcss"; + +@font-face { + font-family: Guardians; + src: url(/Guardians.ttf) format("truetype"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +.font-guardians { + font-family: "Guardians", "Impact", "Arial Black", sans-serif; +} \ No newline at end of file From e79b957d39242836d83f5754aec0c6af60852418 Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 23 Apr 2026 18:46:22 -0400 Subject: [PATCH 09/12] fix: renamed lng to lon --- ui/src/App.svelte | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 5a92052..1116059 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -15,25 +15,25 @@ import { MapLibre, NavigationControl, ScaleControl, GlobeControl, Marker } from 'svelte-maplibre-gl'; import "maplibre-gl/dist/maplibre-gl.css"; - const DEFAULT_GROUND_STATION = { lng: -77.67641, lat: 43.08348 }; + const DEFAULT_GROUND_STATION = { lon: -77.67641, lat: 43.08348 }; const DEFAULT_BACKGROUND_COLOR = "#ffffff"; const DEFAULT_CALL_SIGN = "KE2EGW"; - let groundStationPosition = { lng: -77.67641, lat: 43.08348 }; + let groundStationPosition = { lon: -77.67641, lat: 43.08348 }; let backgroundColor = DEFAULT_BACKGROUND_COLOR; let callSign = DEFAULT_CALL_SIGN; function parseGroundStationParam(value: string | null) { if (!value) return null; - const [latRaw, lngRaw] = value.split(",").map((part) => part.trim()); - if (!latRaw || !lngRaw) return null; + const [latRaw, lonRaw] = value.split(",").map((part) => part.trim()); + if (!latRaw || !lonRaw) return null; const lat = Number(latRaw); - const lng = Number(lngRaw); - if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null; - if (lat < -90 || lat > 90 || lng < -180 || lng > 180) return null; + const lon = Number(lonRaw); + if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null; + if (lat < -90 || lat > 90 || lon < -180 || lon > 180) return null; - return { lat, lng }; + return { lat, lon }; } function applyUrlParameters() { @@ -146,7 +146,7 @@ const latitude = getNumberCaseInsensitive(gnsscoordinates, "latitude"); const longitude = getNumberCaseInsensitive(gnsscoordinates, "longitude"); if (latitude !== null && longitude !== null) { - rocketPosition = { lng: longitude, lat: latitude }; + rocketPosition = { lon: longitude, lat: latitude }; } satCount = getNumberCaseInsensitive(gnsscoordinates, "sat_count"); @@ -257,7 +257,7 @@ @@ -281,7 +281,7 @@
LAT: {rocketPosition.lat !== null ? `${rocketPosition.lat.toFixed(5)}` : "--.-----"}, - LNG: {rocketPosition.lng !== null ? `${rocketPosition.lng.toFixed(5)}` : "--.-----"} + LON: {rocketPosition.lon !== null ? `${rocketPosition.lon.toFixed(5)}` : "--.-----"}
From c5d9429fa1e9a29816a9f1a196b54c8724006313 Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 23 Apr 2026 19:13:11 -0400 Subject: [PATCH 10/12] fix: remove transparency bc green --- ui/src/App.svelte | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 1116059..765a9c9 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -12,7 +12,7 @@ startSineWaveMqttGenerator, stopSineWaveMqttGenerator } from "./stores"; - import { MapLibre, NavigationControl, ScaleControl, GlobeControl, Marker } from 'svelte-maplibre-gl'; + import { MapLibre, Marker } from 'svelte-maplibre-gl'; import "maplibre-gl/dist/maplibre-gl.css"; const DEFAULT_GROUND_STATION = { lon: -77.67641, lat: 43.08348 }; @@ -72,7 +72,7 @@ let gForce: number | null = null; let gForceMax: number = 0.0; const mqttChannel: string | number = "1"; - const ALTITUDE_MAX = 12000; + const ALTITUDE_MAX = 13000; const G_FORCE_MAX = 20; let altitudePercent = 0; let gForcePercent = 0; @@ -163,7 +163,7 @@
-
+
{#each topLeftMetricStubs as metric (metric.label)}
@@ -175,14 +175,14 @@
RISK
@@ -196,7 +196,7 @@ />
-
+
Altitude
@@ -217,7 +217,7 @@
-
+
G Force
@@ -241,13 +241,13 @@
-
+
{callSign ? callSign : "------"}
-
+
Last trans: {secondsSinceLastTransmission !== null ? `${secondsSinceLastTransmission}s` : "------"}
@@ -275,11 +275,11 @@ -
+
SAT: {satCount !== null ? `${satCount}` : "--"}
-
+
LAT: {rocketPosition.lat !== null ? `${rocketPosition.lat.toFixed(5)}` : "--.-----"}, LON: {rocketPosition.lon !== null ? `${rocketPosition.lon.toFixed(5)}` : "--.-----"}
From de56de1eaecfc07e3dd90b9010999f0d7f4a96a1 Mon Sep 17 00:00:00 2001 From: Grayson Siegler Date: Thu, 23 Apr 2026 19:24:21 -0400 Subject: [PATCH 11/12] fix: white logo and black boxes --- ui/public/launchwhite.png | Bin 0 -> 7037 bytes ui/src/App.svelte | 11 +++++------ 2 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 ui/public/launchwhite.png diff --git a/ui/public/launchwhite.png b/ui/public/launchwhite.png new file mode 100644 index 0000000000000000000000000000000000000000..e58170829f8a10877cdeb36ccde65cd3ad0a40a6 GIT binary patch literal 7037 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
-
+
{#each topLeftMetricStubs as metric (metric.label)} -
-
-
{metric.value} {metric.label}
+
+
+
{metric.value} {metric.label}
{/each}
@@ -190,7 +189,7 @@ INITIATIVE
RIT Launch logo From 0517bc4e1b683e13c07f4143835a71147b47568b Mon Sep 17 00:00:00 2001 From: Mia Pigal Date: Sat, 16 May 2026 18:35:33 -0400 Subject: [PATCH 12/12] Revert "fix: don't require database config to start gsw" This reverts commit f3de34d0c753d9cbf8196ccca3aecccd22c014a0. --- cmd/gsw_service.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/gsw_service.go b/cmd/gsw_service.go index e3e61b4..07cef6c 100644 --- a/cmd/gsw_service.go +++ b/cmd/gsw_service.go @@ -128,6 +128,12 @@ func readConfig() (*viper.Viper, int) { logger.Warn("Config file not found, reading config from environment variables") } } + if !config.IsSet("database_host_name") { + logger.Panic("Error reading GSW config: database_host_name not set...") + } + if !config.IsSet("database_port_number") { + logger.Panic("Error reading GSW config: database_port_number not set...") + } return config, *doPprof }