From 1593ac7a7c73d5cdf9468b08ae15cfbcda559802 Mon Sep 17 00:00:00 2001 From: Disy920 Date: Sun, 13 Sep 2026 20:31:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E9=81=A5?= =?UTF-8?q?=E6=B5=8B=E5=B9=B6=E4=BF=AE=E5=A4=8D=E5=90=AF=E5=8A=A8=E5=99=A8?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 51 +- Cargo.toml | 1 - apps/app-frontend/src/App.vue | 91 +- .../src/components/RowDisplay.vue | 9 - .../src/components/home/HomeCalendar.vue | 11 - .../src/components/home/HomeMinimal.vue | 11 - .../src/components/home/HomePinnedServers.vue | 11 - .../src/components/home/HomePinnedWorlds.vue | 16 - .../src/components/home/HomeRecentWorlds.vue | 16 - .../components/home/HomeShortcutWidget.vue | 11 - .../src/components/ui/AccountsCard.vue | 5 - .../src/components/ui/AppActionBar.vue | 6 - .../src/components/ui/ErrorModal.vue | 2 - .../src/components/ui/Instance.vue | 11 - .../src/components/ui/JavaDetectionModal.vue | 5 - .../src/components/ui/JavaSelector.vue | 13 +- .../install_flow/AddServerToInstanceModal.vue | 7 - .../ui/instance_settings/GeneralSettings.vue | 11 - .../InstallationSettings.vue | 28 +- .../ui/modal/PrivacyConsentModal.vue | 145 - .../ui/onboarding/onboardingConfig.ts | 9 - .../ui/settings/DownloadJavaModal.vue | 2 - .../ui/settings/FeatureFlagSettings.vue | 8 - .../components/ui/settings/JavaSettings.vue | 4 - .../ui/settings/PrivacySettings.vue | 156 - .../settings/settings-category-definitions.ts | 10 - .../ui/settings/settings-registry.ts | 4 - .../ui/settings/settings-search-index.ts | 12 - .../ui/settings/settings-search.test.ts | 3 +- .../src/components/ui/world/InstanceItem.vue | 11 - .../src/composables/useDropImport.ts | 5 - .../src/composables/useJavaTest.ts | 11 +- apps/app-frontend/src/helpers/analytics.ts | 75 - apps/app-frontend/src/helpers/instance.ts | 8 - apps/app-frontend/src/helpers/settings.ts | 25 - apps/app-frontend/src/helpers/state.ts | 4 - apps/app-frontend/src/helpers/telemetry.ts | 7 - apps/app-frontend/src/helpers/types.d.ts | 2 - .../app-frontend/src/locales/en-US/index.json | 51 - .../app-frontend/src/locales/zh-CN/index.json | 88 +- .../app-frontend/src/locales/zh-TW/index.json | 51 - apps/app-frontend/src/main.js | 3 - apps/app-frontend/src/pages/Downloads.vue | 6 +- .../app-frontend/src/pages/instance/Index.vue | 11 - apps/app-frontend/src/pages/instance/Mods.vue | 53 - .../src/pages/instance/Worlds.vue | 11 - .../src/pages/project/Gallery.vue | 9 - apps/app-frontend/src/pages/project/Index.vue | 48 - .../src/pages/project/Versions.vue | 25 +- .../src/providers/content-install.ts | 121 - .../src/providers/server-install.ts | 16 - .../src/providers/setup/creation-modal.ts | 7 - apps/app/build.rs | 4 - apps/app/src/api/instance.rs | 12 +- apps/app/src/api/mod.rs | 1 - apps/app/src/api/settings.rs | 24 - apps/app/src/api/telemetry.rs | 10 - apps/app/src/main.rs | 12 - apps/telemetry-dashboard/.dev.vars.example | 9 - apps/telemetry-dashboard/.gitignore | 2 - apps/telemetry-dashboard/.prettierignore | 5 - apps/telemetry-dashboard/README.md | 106 - apps/telemetry-dashboard/app.vue | 6 - .../assets/styles/tailwind.css | 162 - apps/telemetry-dashboard/components.json | 16 - .../components/AppState.vue | 57 - .../components/MetricCard.vue | 50 - .../components/PageHeader.vue | 13 - .../components/charts/DistributionChart.vue | 38 - .../components/charts/TrendChart.vue | 87 - .../components/system/StatusRow.vue | 34 - .../components/ui/Alert.vue | 30 - .../components/ui/Badge.vue | 33 - .../components/ui/Button.vue | 45 - .../components/ui/Card.vue | 20 - .../components/ui/Command.vue | 66 - .../components/ui/DropdownMenu.vue | 79 - .../components/ui/Select.vue | 27 - .../components/ui/Sheet.vue | 44 - .../components/ui/Skeleton.vue | 9 - .../components/ui/Tabs.vue | 30 - .../components/ui/Tooltip.vue | 15 - .../composables/use-dashboard.ts | 9 - .../composables/use-theme.ts | 23 - apps/telemetry-dashboard/eslint.config.mjs | 10 - apps/telemetry-dashboard/layouts/default.vue | 229 - apps/telemetry-dashboard/lib/utils.ts | 6 - apps/telemetry-dashboard/nuxt.config.ts | 70 - apps/telemetry-dashboard/package.json | 51 - apps/telemetry-dashboard/pages/index.vue | 159 - apps/telemetry-dashboard/pages/system.vue | 52 - .../server/api/admin/activity.get.ts | 7 - .../server/api/admin/distributions.get.ts | 7 - .../server/api/admin/overview.get.ts | 7 - .../server/api/admin/session.get.ts | 8 - .../server/api/admin/system.get.ts | 4 - .../server/dev/remote-bindings.ts | 26 - .../server/middleware/admin-auth.ts | 36 - .../server/utils/admin-api.ts | 21 - .../server/utils/admin-http-error.ts | 11 - apps/telemetry-dashboard/server/utils/auth.ts | 78 - .../server/utils/bindings.ts | 11 - .../server/utils/d1-admin-api.ts | 838 ---- .../server/utils/errors.ts | 14 - .../server/utils/handler.ts | 33 - .../server/utils/mock-admin-api.ts | 232 - .../server/utils/service.ts | 48 - .../server/utils/validation.ts | 99 - .../server/utils/vercel-data-source.ts | 153 - .../shared/types/telemetry.ts | 141 - apps/telemetry-dashboard/tailwind.config.ts | 60 - .../test/server/auth.test.ts | 65 - .../test/server/d1-admin-api.test.ts | 233 - apps/telemetry-dashboard/test/server/setup.ts | 31 - .../test/server/validation.test.ts | 24 - .../telemetry-dashboard/test/server/worker.ts | 5 - .../test/ui/states.test.ts | 44 - apps/telemetry-dashboard/test/vue-shim.d.ts | 6 - apps/telemetry-dashboard/tsconfig.json | 7 - apps/telemetry-dashboard/tsconfig.test.json | 7 - apps/telemetry-dashboard/utils/format.ts | 35 - .../vitest.server.config.ts | 22 - apps/telemetry-dashboard/vitest.ui.config.ts | 17 - apps/telemetry-dashboard/wrangler.toml | 23 - apps/telemetry-worker/README.md | 24 - .../telemetry-worker/migrations/0001_init.sql | 219 - .../migrations/0002_optimize_usage.sql | 155 - .../0003_precompute_display_fields.sql | 44 - .../migrations/0004_ingestion_limits.sql | 23 - .../0005_disable_error_telemetry.sql | 24 - apps/telemetry-worker/package.json | 25 - .../scripts/configure-rate-limit.mjs | 81 - apps/telemetry-worker/src/index.ts | 378 -- apps/telemetry-worker/src/redact.ts | 35 - apps/telemetry-worker/src/schema.ts | 34 - apps/telemetry-worker/test/setup.ts | 13 - apps/telemetry-worker/test/worker.test.ts | 210 - apps/telemetry-worker/tsconfig.json | 13 - apps/telemetry-worker/vitest.config.ts | 26 - apps/telemetry-worker/wrangler.toml | 23 - apps/website/package.json | 1 - apps/website/src/pages/privacy.vue | 58 +- apps/website/src/plugins/howxm.client.ts | 9 - packages/app-lib/Cargo.toml | 1 - .../20260913000000_remove-telemetry.sql | 9 + packages/app-lib/src/api/instance.rs | 1 - packages/app-lib/src/api/instance/projects.rs | 7 - packages/app-lib/src/api/instance/run.rs | 198 +- packages/app-lib/src/api/loader_metadata.rs | 18 +- packages/app-lib/src/api/mod.rs | 6 +- .../app-lib/src/api/pack/import/curseforge.rs | 1 - packages/app-lib/src/api/pack/install_from.rs | 24 +- .../app-lib/src/api/pack/install_mrpack.rs | 25 +- packages/app-lib/src/api/settings.rs | 81 +- packages/app-lib/src/error.rs | 3 - packages/app-lib/src/install/runner.rs | 59 +- packages/app-lib/src/launcher/mod.rs | 5 - packages/app-lib/src/lib.rs | 3 +- packages/app-lib/src/state/discord.rs | 238 - packages/app-lib/src/state/friends.rs | 2 - .../commands/apply_content_install.rs | 121 +- .../commands/apply_content_update.rs | 32 +- .../instances/commands/create_instance.rs | 11 +- .../instances/commands/launch_context.rs | 41 - .../state/instances/commands/list_content.rs | 15 +- .../app-lib/src/state/legacy_converter.rs | 6 - packages/app-lib/src/state/mod.rs | 15 +- packages/app-lib/src/state/mr_auth.rs | 2 - packages/app-lib/src/state/process.rs | 21 - packages/app-lib/src/state/settings.rs | 71 +- packages/app-lib/src/telemetry.rs | 391 -- .../app-lib/src/util/download/h2_download.rs | 13 +- packages/app-lib/src/util/fetch.rs | 143 - pnpm-lock.yaml | 4464 ++--------------- pnpm-workspace.yaml | 10 + 175 files changed, 547 insertions(+), 12210 deletions(-) delete mode 100644 apps/app-frontend/src/components/ui/modal/PrivacyConsentModal.vue delete mode 100644 apps/app-frontend/src/components/ui/settings/PrivacySettings.vue delete mode 100644 apps/app-frontend/src/helpers/analytics.ts delete mode 100644 apps/app-frontend/src/helpers/telemetry.ts delete mode 100644 apps/app/src/api/telemetry.rs delete mode 100644 apps/telemetry-dashboard/.dev.vars.example delete mode 100644 apps/telemetry-dashboard/.gitignore delete mode 100644 apps/telemetry-dashboard/.prettierignore delete mode 100644 apps/telemetry-dashboard/README.md delete mode 100644 apps/telemetry-dashboard/app.vue delete mode 100644 apps/telemetry-dashboard/assets/styles/tailwind.css delete mode 100644 apps/telemetry-dashboard/components.json delete mode 100644 apps/telemetry-dashboard/components/AppState.vue delete mode 100644 apps/telemetry-dashboard/components/MetricCard.vue delete mode 100644 apps/telemetry-dashboard/components/PageHeader.vue delete mode 100644 apps/telemetry-dashboard/components/charts/DistributionChart.vue delete mode 100644 apps/telemetry-dashboard/components/charts/TrendChart.vue delete mode 100644 apps/telemetry-dashboard/components/system/StatusRow.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Alert.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Badge.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Button.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Card.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Command.vue delete mode 100644 apps/telemetry-dashboard/components/ui/DropdownMenu.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Select.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Sheet.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Skeleton.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Tabs.vue delete mode 100644 apps/telemetry-dashboard/components/ui/Tooltip.vue delete mode 100644 apps/telemetry-dashboard/composables/use-dashboard.ts delete mode 100644 apps/telemetry-dashboard/composables/use-theme.ts delete mode 100644 apps/telemetry-dashboard/eslint.config.mjs delete mode 100644 apps/telemetry-dashboard/layouts/default.vue delete mode 100644 apps/telemetry-dashboard/lib/utils.ts delete mode 100644 apps/telemetry-dashboard/nuxt.config.ts delete mode 100644 apps/telemetry-dashboard/package.json delete mode 100644 apps/telemetry-dashboard/pages/index.vue delete mode 100644 apps/telemetry-dashboard/pages/system.vue delete mode 100644 apps/telemetry-dashboard/server/api/admin/activity.get.ts delete mode 100644 apps/telemetry-dashboard/server/api/admin/distributions.get.ts delete mode 100644 apps/telemetry-dashboard/server/api/admin/overview.get.ts delete mode 100644 apps/telemetry-dashboard/server/api/admin/session.get.ts delete mode 100644 apps/telemetry-dashboard/server/api/admin/system.get.ts delete mode 100644 apps/telemetry-dashboard/server/dev/remote-bindings.ts delete mode 100644 apps/telemetry-dashboard/server/middleware/admin-auth.ts delete mode 100644 apps/telemetry-dashboard/server/utils/admin-api.ts delete mode 100644 apps/telemetry-dashboard/server/utils/admin-http-error.ts delete mode 100644 apps/telemetry-dashboard/server/utils/auth.ts delete mode 100644 apps/telemetry-dashboard/server/utils/bindings.ts delete mode 100644 apps/telemetry-dashboard/server/utils/d1-admin-api.ts delete mode 100644 apps/telemetry-dashboard/server/utils/errors.ts delete mode 100644 apps/telemetry-dashboard/server/utils/handler.ts delete mode 100644 apps/telemetry-dashboard/server/utils/mock-admin-api.ts delete mode 100644 apps/telemetry-dashboard/server/utils/service.ts delete mode 100644 apps/telemetry-dashboard/server/utils/validation.ts delete mode 100644 apps/telemetry-dashboard/server/utils/vercel-data-source.ts delete mode 100644 apps/telemetry-dashboard/shared/types/telemetry.ts delete mode 100644 apps/telemetry-dashboard/tailwind.config.ts delete mode 100644 apps/telemetry-dashboard/test/server/auth.test.ts delete mode 100644 apps/telemetry-dashboard/test/server/d1-admin-api.test.ts delete mode 100644 apps/telemetry-dashboard/test/server/setup.ts delete mode 100644 apps/telemetry-dashboard/test/server/validation.test.ts delete mode 100644 apps/telemetry-dashboard/test/server/worker.ts delete mode 100644 apps/telemetry-dashboard/test/ui/states.test.ts delete mode 100644 apps/telemetry-dashboard/test/vue-shim.d.ts delete mode 100644 apps/telemetry-dashboard/tsconfig.json delete mode 100644 apps/telemetry-dashboard/tsconfig.test.json delete mode 100644 apps/telemetry-dashboard/utils/format.ts delete mode 100644 apps/telemetry-dashboard/vitest.server.config.ts delete mode 100644 apps/telemetry-dashboard/vitest.ui.config.ts delete mode 100644 apps/telemetry-dashboard/wrangler.toml delete mode 100644 apps/telemetry-worker/README.md delete mode 100644 apps/telemetry-worker/migrations/0001_init.sql delete mode 100644 apps/telemetry-worker/migrations/0002_optimize_usage.sql delete mode 100644 apps/telemetry-worker/migrations/0003_precompute_display_fields.sql delete mode 100644 apps/telemetry-worker/migrations/0004_ingestion_limits.sql delete mode 100644 apps/telemetry-worker/migrations/0005_disable_error_telemetry.sql delete mode 100644 apps/telemetry-worker/package.json delete mode 100644 apps/telemetry-worker/scripts/configure-rate-limit.mjs delete mode 100644 apps/telemetry-worker/src/index.ts delete mode 100644 apps/telemetry-worker/src/redact.ts delete mode 100644 apps/telemetry-worker/src/schema.ts delete mode 100644 apps/telemetry-worker/test/setup.ts delete mode 100644 apps/telemetry-worker/test/worker.test.ts delete mode 100644 apps/telemetry-worker/tsconfig.json delete mode 100644 apps/telemetry-worker/vitest.config.ts delete mode 100644 apps/telemetry-worker/wrangler.toml delete mode 100644 apps/website/src/plugins/howxm.client.ts create mode 100644 packages/app-lib/migrations/20260913000000_remove-telemetry.sql delete mode 100644 packages/app-lib/src/state/discord.rs delete mode 100644 packages/app-lib/src/telemetry.rs diff --git a/Cargo.lock b/Cargo.lock index 7cda147..8a8a4c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ dependencies = [ "serde_json", "thiserror 2.0.19", "utoipa", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -707,7 +707,7 @@ checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" dependencies = [ "byteorder", "fnv", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -1431,21 +1431,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "discord-rich-presence" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c55d69cab17c19677ce3a5f8face993a9e6eaf847fecac3547f3a3ff4a2494" -dependencies = [ - "log", - "serde", - "serde_derive", - "serde_json", - "serde_repr", - "thiserror 2.0.19", - "uuid 0.8.2", -] - [[package]] name = "dispatch2" version = "0.3.1" @@ -3570,7 +3555,7 @@ dependencies = [ "portable-atomic", "smallvec", "tagptr", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -5300,7 +5285,7 @@ dependencies = [ "serde", "serde_json", "url", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -5904,7 +5889,7 @@ dependencies = [ "tokio-stream", "tracing", "url", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -5984,7 +5969,7 @@ dependencies = [ "stringprep", "thiserror 2.0.19", "tracing", - "uuid 1.24.0", + "uuid", "whoami", ] @@ -6022,7 +6007,7 @@ dependencies = [ "stringprep", "thiserror 2.0.19", "tracing", - "uuid 1.24.0", + "uuid", "whoami", ] @@ -6048,7 +6033,7 @@ dependencies = [ "thiserror 2.0.19", "tracing", "url", - "uuid 1.24.0", + "uuid", ] [[package]] @@ -6454,7 +6439,7 @@ dependencies = [ "thiserror 2.0.19", "time", "url", - "uuid 1.24.0", + "uuid", "walkdir", ] @@ -6762,7 +6747,7 @@ dependencies = [ "toml 1.1.3+spec-1.1.0", "url", "urlpattern", - "uuid 1.24.0", + "uuid", "walkdir", ] @@ -6833,7 +6818,6 @@ dependencies = [ "data-url", "derive_more", "dirs", - "discord-rich-presence", "dotenvy", "dunce", "either", @@ -6901,7 +6885,7 @@ dependencies = [ "tracing-subscriber", "url", "urlencoding", - "uuid 1.24.0", + "uuid", "webpki-roots", "whoami", "windows 0.61.3", @@ -6967,7 +6951,7 @@ dependencies = [ "trash", "url", "urlencoding", - "uuid 1.24.0", + "uuid", "windows 0.61.3", "zip 6.0.0", ] @@ -7691,15 +7675,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.17", -] - [[package]] name = "uuid" version = "1.24.0" @@ -8868,7 +8843,7 @@ dependencies = [ "tokio", "tracing", "uds_windows", - "uuid 1.24.0", + "uuid", "windows-sys 0.61.2", "winnow 1.0.4", "zbus_macros", diff --git a/Cargo.toml b/Cargo.toml index 6a26ddb..f061790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ dashmap = "6.1.0" data-url = "0.3.2" derive_more = "2.1.1" dirs = "6.0.0" -discord-rich-presence = "1.0.0" dotenvy = "0.15.7" dunce = "1.0.5" either = "1.15.0" diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index dd3c24a..9c9220a 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -85,7 +85,6 @@ import InstanceIconPickerModal from '@/components/ui/modal/InstanceIconPickerMod import JavaDownloadConfirmationModal from '@/components/ui/modal/JavaDownloadConfirmationModal.vue' import ModpackAlreadyInstalledModal from '@/components/ui/modal/ModpackAlreadyInstalledModal.vue' import ModpackInstallModal from '@/components/ui/modal/ModpackInstallModal.vue' -import PrivacyConsentModal from '@/components/ui/modal/PrivacyConsentModal.vue' import UpdateToPlayModal from '@/components/ui/modal/UpdateToPlayModal.vue' import NavButton from '@/components/ui/NavButton.vue' import NavRail from '@/components/ui/NavRail.vue' @@ -98,7 +97,6 @@ import { useDropImport } from '@/composables/useDropImport' import { minecraftLaunchErrorKey } from '@/composables/useMinecraftLaunchError' import { useNetworkStatus } from '@/composables/useNetworkStatus' import { AxolotlBrandConfig, config, getOfficialLabrinthBaseUrl } from '@/config' -import { trackEvent } from '@/helpers/analytics' import { check_reachable } from '@/helpers/auth.js' import { get_user, get_version } from '@/helpers/cache.js' import { configureCurseForgeManualDownloadWatcher } from '@/helpers/curseforge' @@ -119,16 +117,13 @@ import { mergeUrlQuery, parseModrinthLink } from '@/helpers/project-links.ts' import { get as getSettings, getLastBrowseContentProjectType, - getPrivacySettings, getUpdateChannel, getUpdatePreferences, isBrowseContentProjectType, - type PrivacySettings, - savePrivacySettings, set as setSettings, } from '@/helpers/settings.ts' import { getSidebarExpanded, setSidebarExpanded } from '@/helpers/sidebar-state.ts' -import { get_opening_command, initialize_state, set_discord_activity } from '@/helpers/state' +import { get_opening_command, initialize_state } from '@/helpers/state' import { areUpdatesEnabled, backupAppDbForUpdate, @@ -369,8 +364,6 @@ watch( ) const stateInitialized = ref(false) -const privacyConsentModal = ref>() -const privacyConsentPending = ref(false) const closeChoiceModal = ref>() const closeChoiceOpen = ref(false) const closeChoiceRemember = ref(false) @@ -1055,9 +1048,6 @@ async function setupApp() { theme, accent_color, locale, - telemetry, - telemetry_consent_version, - discord_rpc, collapsed_navigation, hide_nametag_skins_page, advanced_rendering, @@ -1101,7 +1091,6 @@ async function setupApp() { const dev = await isDev() isDevEnvironment.value = dev if (!onboarded && route.path !== '/') await router.replace('/') - privacyConsentPending.value = telemetry_consent_version < 1 showOnboarding.value = false onboardingSettings.value = initialSettings @@ -1132,16 +1121,7 @@ async function setupApp() { themeStore.devMode = developer_mode themeStore.featureFlags = feature_flags stateInitialized.value = true - if (privacyConsentPending.value) { - await nextTick() - privacyConsentModal.value?.show({ - telemetry, - discord_rpc, - consent_version: telemetry_consent_version, - }) - } else { - showOnboarding.value = !onboarded - } + showOnboarding.value = !onboarded void reconcileMojangAuthSourceAtStartup().catch(handleError) isMaximized.value = await getCurrentWindow().isMaximized() @@ -1274,42 +1254,7 @@ async function closeOnboardingSettings() { } async function scheduleStartupDialogs() { - if (!stateInitialized.value || privacyConsentPending.value || showOnboarding.value) return -} - -async function handlePrivacyConsentSaved(privacy: PrivacySettings) { - privacyConsentPending.value = false - if (onboardingSettings.value) { - onboardingSettings.value.telemetry = privacy.telemetry - onboardingSettings.value.discord_rpc = privacy.discord_rpc - onboardingSettings.value.telemetry_consent_version = privacy.consent_version - } - if (!onboardingSettings.value?.onboarded) { - startOnboarding('main') - } else { - await scheduleStartupDialogs() - } -} - -async function previewPrivacyConsentModal() { - try { - const current = await getPrivacySettings() - const privacy = await savePrivacySettings({ - telemetry: false, - discord_rpc: current.discord_rpc, - consent_version: 0, - }) - privacyConsentPending.value = true - if (onboardingSettings.value) { - onboardingSettings.value.telemetry = privacy.telemetry - onboardingSettings.value.discord_rpc = privacy.discord_rpc - onboardingSettings.value.telemetry_consent_version = privacy.consent_version - } - await nextTick() - privacyConsentModal.value?.show(privacy) - } catch (error) { - handleError(error) - } + if (!stateInitialized.value || showOnboarding.value) return } provide('replayOnboarding', replayOnboarding) @@ -1320,7 +1265,6 @@ provide( ) provide('previewMinecraftCrashModal', () => minecraftCrashModal.value?.showPreview()) provide('showLauncherPopup', (_request: unknown) => {}) -provide('previewPrivacyConsentModal', previewPrivacyConsentModal) const stateFailed = ref(false) stateInitialization @@ -1429,9 +1373,6 @@ loading.setEnabled(false) let initialLoadToken = loading.begin() let routerToken = null let suspenseToken = null -let lastDiscordActivity = null -let discordActivityUpdate = Promise.resolve() - let suspensePending = false const sidebarOverlayScrollbarsOptions = Object.freeze({ @@ -1447,31 +1388,11 @@ router.beforeEach(() => { routerToken = loading.begin() }) -function syncDiscordActivity(to: RouteLocationNormalizedLoaded) { - const activity = - typeof to.meta.discordActivity === 'string' ? to.meta.discordActivity : 'Idling...' - if (activity === lastDiscordActivity) return - - lastDiscordActivity = activity - discordActivityUpdate = discordActivityUpdate - .then(() => set_discord_activity(activity)) - .catch((error) => { - if (lastDiscordActivity === activity) lastDiscordActivity = null - console.error('Failed to update Discord activity', error) - }) -} - router.afterEach((to, from, failure) => { hideAllPoppers() if (!failure) void invoke('lightweight_mode_set_route', { route: to.fullPath }) - trackEvent('PageView', { - path: to.path, - fromPath: from.path, - failed: failure, - }) if (!failure) { void directLinkSync?.() - if (stateInitialized.value) syncDiscordActivity(to) } setTimeout(() => { if (!suspensePending && stateInitialized.value) { @@ -1508,7 +1429,6 @@ watch( stateInitialized, (ready) => { if (ready) { - syncDiscordActivity(router.currentRoute.value) if (initialLoadToken) { loading.end(initialLoadToken) initialLoadToken = null @@ -1624,7 +1544,6 @@ const dropImport = useDropImport({ onSkinsPage, onSchematicWorkshopPage, isSchematicFile, - trackEvent, router, }) @@ -1836,9 +1755,6 @@ async function handleCommand(e) { } else { await install_create_modpack_instance(location).catch(handleError) } - trackEvent('InstanceCreate', { - source: 'CreationModalFileDrop', - }) } } else if (e.event === 'LaunchInstance') { const instance = await getInstance(e.id).catch(() => null) @@ -2577,7 +2493,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload) /> - { }) if (!handled) handleSevereError(err, { instanceId: args.item.id }) }) - trackEvent('InstanceStart', { - loader: args.item.loader, - game_version: args.item.game_version, - }) break case 'stop': await kill(args.item.id).catch(handleError) - trackEvent('InstanceStop', { - loader: args.item.loader, - game_version: args.item.game_version, - }) break case 'add_content': await router.push({ diff --git a/apps/app-frontend/src/components/home/HomeCalendar.vue b/apps/app-frontend/src/components/home/HomeCalendar.vue index 27ee182..b3dda6a 100644 --- a/apps/app-frontend/src/components/home/HomeCalendar.vue +++ b/apps/app-frontend/src/components/home/HomeCalendar.vue @@ -18,7 +18,6 @@ import { computed, ref, watch } from 'vue' import { useHomeDashboardRuntime } from '@/components/home/home-dashboard-runtime' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { type DailyPlaytime, type DailyPlaytimeEntry, @@ -200,11 +199,6 @@ function selectDay(dateKey: string) { async function playInstance(instance: GameInstance) { try { await run(instance.id) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeCalendar', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -216,11 +210,6 @@ async function playInstance(instance: GameInstance) { async function stopInstance(instance: GameInstance) { await kill(instance.id).catch(handleError) - trackEvent('InstanceStop', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeCalendar', - }) } watch(() => anchor.value.getTime(), refreshPlaytime, { immediate: true }) diff --git a/apps/app-frontend/src/components/home/HomeMinimal.vue b/apps/app-frontend/src/components/home/HomeMinimal.vue index afb3884..865498f 100644 --- a/apps/app-frontend/src/components/home/HomeMinimal.vue +++ b/apps/app-frontend/src/components/home/HomeMinimal.vue @@ -25,7 +25,6 @@ import HomeGreeting from '@/components/home/HomeGreeting.vue' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' import { useNetworkStatus } from '@/composables/useNetworkStatus' -import { trackEvent } from '@/helpers/analytics' import { process_listener } from '@/helpers/events' import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install' import { kill, run } from '@/helpers/instance' @@ -126,11 +125,6 @@ async function playInstance() { loading.value = true try { await run(instance.id) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeMinimal', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -149,11 +143,6 @@ async function stopInstance() { await kill(instance.id).catch(handleError) running.value = false - trackEvent('InstanceStop', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeMinimal', - }) } async function installInstance() { diff --git a/apps/app-frontend/src/components/home/HomePinnedServers.vue b/apps/app-frontend/src/components/home/HomePinnedServers.vue index dd07f0a..9a66cdb 100644 --- a/apps/app-frontend/src/components/home/HomePinnedServers.vue +++ b/apps/app-frontend/src/components/home/HomePinnedServers.vue @@ -22,7 +22,6 @@ import { computed, ref } from 'vue' import type { HomeWidgetSize } from '@/components/home/home-dashboard' import { useHomeDashboardRuntime } from '@/components/home/home-dashboard-runtime' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { kill } from '@/helpers/instance' import type { GameInstance } from '@/helpers/types' import { @@ -107,11 +106,6 @@ async function joinServer(world: ServerWorld & WorldWithInstance, instance: Game try { await start_join_server(world.instance_id, world.address) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomePinnedServer', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -125,11 +119,6 @@ async function joinServer(world: ServerWorld & WorldWithInstance, instance: Game async function stopInstance(instance: GameInstance) { await kill(instance.id).catch(handleError) - trackEvent('InstanceStop', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomePinnedServer', - }) } async function unpinServer(world: ServerWorld & WorldWithInstance) { diff --git a/apps/app-frontend/src/components/home/HomePinnedWorlds.vue b/apps/app-frontend/src/components/home/HomePinnedWorlds.vue index 53e5457..ef7c7f0 100644 --- a/apps/app-frontend/src/components/home/HomePinnedWorlds.vue +++ b/apps/app-frontend/src/components/home/HomePinnedWorlds.vue @@ -7,7 +7,6 @@ import { getHomeWidgetCardDensity, type HomeWidgetSize } from '@/components/home import { useHomeDashboardRuntime } from '@/components/home/home-dashboard-runtime' import WorldItem from '@/components/ui/world/WorldItem.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { kill, run } from '@/helpers/instance' import type { GameInstance } from '@/helpers/types' import { @@ -73,11 +72,6 @@ async function joinWorld(world: WorldWithInstance, instance: GameInstance) { try { await start_join_singleplayer_world(world.instance_id, world.path) playingWorldKey.value = key - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomePinnedWorld', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -92,11 +86,6 @@ async function joinWorld(world: WorldWithInstance, instance: GameInstance) { async function playInstance(instance: GameInstance) { try { await run(instance.id) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomePinnedWorld', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -109,11 +98,6 @@ async function playInstance(instance: GameInstance) { async function stopInstance(instance: GameInstance) { await kill(instance.id).catch(handleError) playingWorldKey.value = null - trackEvent('InstanceStop', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomePinnedWorld', - }) } diff --git a/apps/app-frontend/src/components/home/HomeRecentWorlds.vue b/apps/app-frontend/src/components/home/HomeRecentWorlds.vue index e5db530..eb78c73 100644 --- a/apps/app-frontend/src/components/home/HomeRecentWorlds.vue +++ b/apps/app-frontend/src/components/home/HomeRecentWorlds.vue @@ -15,7 +15,6 @@ import { useHomeDashboardRuntime } from '@/components/home/home-dashboard-runtim import InstanceItem from '@/components/ui/world/InstanceItem.vue' import WorldItem from '@/components/ui/world/WorldItem.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { kill, run } from '@/helpers/instance' import type { GameInstance } from '@/helpers/types' import { @@ -117,11 +116,6 @@ async function joinWorld(world: WorldWithInstance, instance: GameInstance) { await start_join_singleplayer_world(world.instance_id, world.path) } playingWorldKey.value = key - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeRecentWorld', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -136,11 +130,6 @@ async function joinWorld(world: WorldWithInstance, instance: GameInstance) { async function playInstance(instance: GameInstance) { try { await run(instance.id) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeRecentWorld', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.id, @@ -153,11 +142,6 @@ async function playInstance(instance: GameInstance) { async function stopInstance(instance: GameInstance) { await kill(instance.id).catch(handleError) playingWorldKey.value = null - trackEvent('InstanceStop', { - loader: instance.loader, - game_version: instance.game_version, - source: 'HomeRecentWorld', - }) } diff --git a/apps/app-frontend/src/components/home/HomeShortcutWidget.vue b/apps/app-frontend/src/components/home/HomeShortcutWidget.vue index f92e6f1..f6b962d 100644 --- a/apps/app-frontend/src/components/home/HomeShortcutWidget.vue +++ b/apps/app-frontend/src/components/home/HomeShortcutWidget.vue @@ -28,7 +28,6 @@ import type { HomeWidgetPlacement, HomeWidgetSize } from '@/components/home/home import { useHomeDashboardRuntime } from '@/components/home/home-dashboard-runtime' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { kill, run } from '@/helpers/instance' import type { GameInstance } from '@/helpers/types' import { @@ -205,11 +204,6 @@ async function playInstance(targetInstance: GameInstance) { starting.value = true try { await run(targetInstance.id) - trackEvent('InstanceStart', { - loader: targetInstance.loader, - game_version: targetInstance.game_version, - source: 'HomeInstanceWidget', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: targetInstance.id, @@ -230,11 +224,6 @@ async function playWorld() { } else { await start_join_singleplayer_world(instance.value.id, world.value.path) } - trackEvent('InstanceStart', { - loader: instance.value.loader, - game_version: instance.value.game_version, - source: 'HomeShortcutWidget', - }) } catch (error) { const handled = await handleMinecraftLaunchError(error, { instance_id: instance.value.id, diff --git a/apps/app-frontend/src/components/ui/AccountsCard.vue b/apps/app-frontend/src/components/ui/AccountsCard.vue index 2844f76..88a13c2 100644 --- a/apps/app-frontend/src/components/ui/AccountsCard.vue +++ b/apps/app-frontend/src/components/ui/AccountsCard.vue @@ -280,7 +280,6 @@ import MinecraftLoginModal from '@/components/ui/MinecraftLoginModal.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import { useNetworkStatus } from '@/composables/useNetworkStatus' import { compareMinecraftAccounts } from '@/helpers/accounts' -import { trackEvent } from '@/helpers/analytics' import { begin_yggdrasil_login, delete_yggdrasil_password, @@ -678,7 +677,6 @@ async function onMicrosoftLogin(account: MinecraftCredential) { loginDisabled.value = true try { await setAccount(account) - trackEvent('AccountLogIn') } catch (error) { handleSevereError(error) } finally { @@ -833,7 +831,6 @@ async function addYggdrasilAccount() { await persistYggdrasilPasswordPreference() yggdrasilAccountModal.value?.hide() await setAccount(result.credentials) - trackEvent('YggdrasilAccountAdd') } else { pendingYggdrasilFlowId.value = result.flow_id pendingYggdrasilProfiles.value = result.profiles @@ -859,7 +856,6 @@ async function selectYggdrasilProfile(profileId: string) { await persistYggdrasilPasswordPreference() yggdrasilProfileModal.value?.hide() await setAccount(account) - trackEvent('YggdrasilAccountAdd') } catch (error) { handleError(error as Error) } finally { @@ -875,7 +871,6 @@ async function logout(account: MinecraftCredential) { } else { notifyAccountChange() } - trackEvent('AccountLogOut') } async function copyAccountUuid(account: MinecraftCredential) { diff --git a/apps/app-frontend/src/components/ui/AppActionBar.vue b/apps/app-frontend/src/components/ui/AppActionBar.vue index 9633a21..b963bf8 100644 --- a/apps/app-frontend/src/components/ui/AppActionBar.vue +++ b/apps/app-frontend/src/components/ui/AppActionBar.vue @@ -212,7 +212,6 @@ import { useRoute, useRouter } from 'vue-router' import AppUpdateButton from '@/components/ui/app-update-button/index.vue' import { useInstallJobNotifications } from '@/composables/browse/install-job-notifications' import { useNetworkStatus } from '@/composables/useNetworkStatus' -import { trackEvent } from '@/helpers/analytics' import { loading_listener, process_listener } from '@/helpers/events' import { get_many as getInstances } from '@/helpers/instance' import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process' @@ -437,11 +436,6 @@ const stop = async (process: RunningProcess) => { try { await killProcess(process.uuid).catch(handleError) - trackEvent('InstanceStop', { - loader: process.instance.loader, - game_version: process.instance.game_version, - source: 'AppBar', - }) } catch (e) { console.error(e) } diff --git a/apps/app-frontend/src/components/ui/ErrorModal.vue b/apps/app-frontend/src/components/ui/ErrorModal.vue index 6bc1e6e..d02dd9c 100644 --- a/apps/app-frontend/src/components/ui/ErrorModal.vue +++ b/apps/app-frontend/src/components/ui/ErrorModal.vue @@ -23,7 +23,6 @@ import { computed, ref } from 'vue' import { ChatIcon } from '@/assets/icons' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import { AxolotlBrandConfig } from '@/config' -import { trackEvent } from '@/helpers/analytics' import { login as login_flow, set_default_user } from '@/helpers/auth.js' import { install_existing_instance } from '@/helpers/install' import { cancel_directory_change } from '@/helpers/settings.ts' @@ -241,7 +240,6 @@ async function loginMinecraft() { await set_default_user(loggedIn.profile.id).catch(handleError) } - await trackEvent('AccountLogIn', { source: 'ErrorModal' }) loadingMinecraft.value = false errorModal.value.hide() } catch (err) { diff --git a/apps/app-frontend/src/components/ui/Instance.vue b/apps/app-frontend/src/components/ui/Instance.vue index b6ea179..56b5ff3 100644 --- a/apps/app-frontend/src/components/ui/Instance.vue +++ b/apps/app-frontend/src/components/ui/Instance.vue @@ -23,7 +23,6 @@ import { useRouter } from 'vue-router' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' import { useNetworkStatus } from '@/composables/useNetworkStatus' -import { trackEvent } from '@/helpers/analytics' import { process_listener } from '@/helpers/events' import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install' import { kill, run } from '@/helpers/instance' @@ -121,11 +120,6 @@ const play = async (e, context) => { if (!handled) handleSevereError(err, { instanceId: props.instance.id }) }) .finally(() => { - trackEvent('InstanceStart', { - loader: props.instance.loader, - game_version: props.instance.game_version, - source: context, - }) }) loading.value = false } @@ -136,11 +130,6 @@ const stop = async (e, context) => { await kill(props.instance.id).catch(handleError) - trackEvent('InstanceStop', { - loader: props.instance.loader, - game_version: props.instance.game_version, - source: context, - }) } const repair = async (e) => { diff --git a/apps/app-frontend/src/components/ui/JavaDetectionModal.vue b/apps/app-frontend/src/components/ui/JavaDetectionModal.vue index b341f69..8fe3ffb 100644 --- a/apps/app-frontend/src/components/ui/JavaDetectionModal.vue +++ b/apps/app-frontend/src/components/ui/JavaDetectionModal.vue @@ -59,7 +59,6 @@ import { import { onUnmounted, ref } from 'vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' -import { trackEvent } from '@/helpers/analytics' import { java_discovery_listener } from '@/helpers/events' import { find_filtered_jres } from '@/helpers/jre.js' @@ -131,9 +130,5 @@ const emit = defineEmits(['submit']) function setJavaInstall(javaInstall) { emit('submit', javaInstall) detectJavaModal.value.hide() - trackEvent('JavaAutoDetect', { - path: javaInstall.path, - version: javaInstall.version, - }) } diff --git a/apps/app-frontend/src/components/ui/JavaSelector.vue b/apps/app-frontend/src/components/ui/JavaSelector.vue index 8e15e1b..e44a111 100644 --- a/apps/app-frontend/src/components/ui/JavaSelector.vue +++ b/apps/app-frontend/src/components/ui/JavaSelector.vue @@ -112,7 +112,6 @@ import { computed, ref, watch } from 'vue' import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue' import useJavaTest from '@/composables/useJavaTest' -import { trackEvent } from '@/helpers/analytics' import { auto_install_java, find_filtered_jres, get_jre } from '@/helpers/jre.js' const { handleError } = injectNotificationManager() @@ -196,9 +195,9 @@ const recommendedInstalled = computed(() => { let hasInitialized = false async function runTest(path) { - await testJavaInstallation(path, testVersion.value, true) + await testJavaInstallation(path, testVersion.value) if (props.version != null) { - await recommendedJavaTest.testJavaInstallation(path, props.version, false) + await recommendedJavaTest.testJavaInstallation(path, props.version) } } @@ -212,9 +211,9 @@ watch( (newPath) => { if (newPath) { if (!hasInitialized) { - testJavaInstallation(newPath, testVersion.value, false) + testJavaInstallation(newPath, testVersion.value) if (props.version != null) { - recommendedJavaTest.testJavaInstallation(newPath, props.version, false) + recommendedJavaTest.testJavaInstallation(newPath, props.version) } hasInitialized = true } else { @@ -242,9 +241,6 @@ async function handleJavaFileInput() { } } - trackEvent('JavaManualSelect', { - version: props.version, - }) commitSelection(result) } @@ -279,7 +275,6 @@ async function reinstallJava() { } } - trackEvent('JavaReInstall', { path: path, version: props.version }) commitSelection(result) runTest(result.path) } finally { diff --git a/apps/app-frontend/src/components/ui/install_flow/AddServerToInstanceModal.vue b/apps/app-frontend/src/components/ui/install_flow/AddServerToInstanceModal.vue index 708849d..6dec1c1 100644 --- a/apps/app-frontend/src/components/ui/install_flow/AddServerToInstanceModal.vue +++ b/apps/app-frontend/src/components/ui/install_flow/AddServerToInstanceModal.vue @@ -14,7 +14,6 @@ import { computed, ref } from 'vue' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' -import { trackEvent } from '@/helpers/analytics' import { list } from '@/helpers/instance' import { add_server_to_instance, get_instance_worlds } from '@/helpers/worlds.ts' @@ -91,7 +90,6 @@ defineExpose({ instances.value = instanceValues modal.value.show() - trackEvent('AddServerToInstanceStart', { source: 'AddServerToInstanceModal' }) }, }) @@ -102,11 +100,6 @@ async function addServer(instance) { instance.added = true await queryClient.invalidateQueries({ queryKey: ['worlds', instance.id] }) - trackEvent('AddServerToInstance', { - server_name: serverName.value, - instance_name: instance.name, - source: 'AddServerToInstanceModal', - }) } catch (err) { handleError(err) } diff --git a/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue index a0c2475..7561487 100644 --- a/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue +++ b/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue @@ -18,7 +18,6 @@ import { useRouter } from 'vue-router' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue' -import { trackEvent } from '@/helpers/analytics' import { install_duplicate_instance } from '@/helpers/install' import { edit, edit_icon, get_full_path, remove } from '@/helpers/instance' import { injectInstanceSettings } from '@/providers/instance-settings' @@ -49,10 +48,6 @@ const installing = computed(() => instance.value.install_stage !== 'installed') async function duplicateInstance() { await install_duplicate_instance(instance.value.id).catch(handleError) - trackEvent('InstanceDuplicate', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) } function formatReleaseChannelLabel(channel: ReleaseChannel) { @@ -104,7 +99,6 @@ watch(selectedReleaseChannel, async (channel, previousChannel) => { async function resetIcon() { icon.value = undefined await edit_icon(instance.value.id, null).catch(handleError) - trackEvent('InstanceRemoveIcon') } async function setIcon() { @@ -116,7 +110,6 @@ async function setIcon() { icon.value = picked.path try { await edit_icon(instance.value.id, picked.path) - trackEvent('InstanceSetIcon') } catch (error) { icon.value = previousIcon handleError(error) @@ -253,10 +246,6 @@ async function removeInstance() { removing.value = true const path = instance.value.id - trackEvent('InstanceRemove', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) await router.push({ path: '/' }) await remove(path).catch(handleError) diff --git a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue index 7c223e7..a7058fc 100644 --- a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue +++ b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue @@ -22,7 +22,6 @@ import { useQuery, useQueryClient } from '@tanstack/vue-query' import { computed, ref } from 'vue' import SymlinkInstanceWarning from '@/components/ui/SymlinkInstanceWarning.vue' -import { trackEvent } from '@/helpers/analytics' import { get_project_versions, get_version } from '@/helpers/cache' import { type CurseForgeFile, updateManagedCurseForgeModpack } from '@/helpers/curseforge' import { @@ -333,10 +332,6 @@ provideInstallationSettings({ afterSave: async () => { debug('afterSave: installing', { instanceId: instance.value.id }) await install_existing_instance(instance.value.id, false).catch(handleError) - trackEvent('InstanceRepair', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) debug('afterSave: done') }, @@ -345,40 +340,27 @@ provideInstallationSettings({ repairing.value = true await install_existing_instance(instance.value.id, true).catch(handleError) repairing.value = false - trackEvent('InstanceRepair', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) debug('repair: done') }, async reinstallModpack() { debug('reinstallModpack: called', { instanceId: instance.value.id }) reinstalling.value = true - let shouldTrack = false try { if (isImportedModpack.value) { - shouldTrack = await installLocalModpackFromPicker() + await installLocalModpackFromPicker() } else if (isCurseForgeLinkedModpack.value) { const fileId = Number(instance.value.link?.version_id) if (!Number.isFinite(fileId)) { throw new Error('Invalid CurseForge file ID') } await updateManagedCurseForgeModpack(instance.value.id, fileId).catch(handleError) - shouldTrack = true } else { await update_repair_modrinth(instance.value.id).catch(handleError) - shouldTrack = true } } finally { reinstalling.value = false } - if (shouldTrack) { - trackEvent('InstanceRepair', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) - } debug('reinstallModpack: done') }, @@ -386,13 +368,7 @@ provideInstallationSettings({ debug('swapModpack: called', { instanceId: instance.value.id }) reinstalling.value = true try { - const installed = await installLocalModpackFromPicker() - if (installed) { - trackEvent('InstanceRepair', { - loader: instance.value.loader, - game_version: instance.value.game_version, - }) - } + await installLocalModpackFromPicker() } finally { reinstalling.value = false } diff --git a/apps/app-frontend/src/components/ui/modal/PrivacyConsentModal.vue b/apps/app-frontend/src/components/ui/modal/PrivacyConsentModal.vue deleted file mode 100644 index 7b4f2d1..0000000 --- a/apps/app-frontend/src/components/ui/modal/PrivacyConsentModal.vue +++ /dev/null @@ -1,145 +0,0 @@ - - - diff --git a/apps/app-frontend/src/components/ui/onboarding/onboardingConfig.ts b/apps/app-frontend/src/components/ui/onboarding/onboardingConfig.ts index 57de1c8..289a66f 100644 --- a/apps/app-frontend/src/components/ui/onboarding/onboardingConfig.ts +++ b/apps/app-frontend/src/components/ui/onboarding/onboardingConfig.ts @@ -204,15 +204,6 @@ export const onboardingMessages = defineMessages({ defaultMessage: 'Choose how content downloads and installs, from download sources to safety checks.', }, - privacyTitle: { - id: 'app.onboarding.privacy.title', - defaultMessage: 'Your data, your call', - }, - privacyDescription: { - id: 'app.onboarding.privacy.description', - defaultMessage: - 'Manage anonymous telemetry, Discord Rich Presence, and the Minecraft log analysis service whenever you need to.', - }, updatesTitle: { id: 'app.onboarding.updates.title', defaultMessage: 'Stay in the loop' }, updatesDescription: { id: 'app.onboarding.updates.description', diff --git a/apps/app-frontend/src/components/ui/settings/DownloadJavaModal.vue b/apps/app-frontend/src/components/ui/settings/DownloadJavaModal.vue index 3b617a3..724005a 100644 --- a/apps/app-frontend/src/components/ui/settings/DownloadJavaModal.vue +++ b/apps/app-frontend/src/components/ui/settings/DownloadJavaModal.vue @@ -21,7 +21,6 @@ import JetBrainsLogo from '@/assets/java-vendors/jetbrains.png' import MicrosoftLogo from '@/assets/java-vendors/microsoft.png' import OracleLogo from '@/assets/java-vendors/oracle.png' import SapLogo from '@/assets/java-vendors/sap.png' -import { trackEvent } from '@/helpers/analytics' import { download_java, list_java_feed_vendors, list_java_feed_versions } from '@/helpers/jre' const { handleError } = injectNotificationManager() @@ -117,7 +116,6 @@ function backToVendors() { async function downloadVersion(info) { downloading.value = info.major_version - trackEvent('JavaDownload', { vendor: info.vendor, version: info.major_version }) modal.value?.hide() const job = await download_java(info.vendor, info.major_version).catch(handleError) diff --git a/apps/app-frontend/src/components/ui/settings/FeatureFlagSettings.vue b/apps/app-frontend/src/components/ui/settings/FeatureFlagSettings.vue index faef5b1..c8f5ed3 100644 --- a/apps/app-frontend/src/components/ui/settings/FeatureFlagSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/FeatureFlagSettings.vue @@ -23,7 +23,6 @@ const { formatMessage } = useVIntl() const { addNotification } = injectNotificationManager() const isDevEnvironment = await isDev() const previewMinecraftCrashModal = inject<() => void>('previewMinecraftCrashModal') -const previewPrivacyConsentModal = inject<() => Promise>('previewPrivacyConsentModal') const messages = defineMessages({ resetToDefault: { id: 'app.settings.feature-flags.reset-to-default', @@ -53,10 +52,6 @@ const messages = defineMessages({ id: 'app.settings.about.preview-minecraft-crash-modal', defaultMessage: 'Preview Minecraft crash window', }, - previewPrivacyConsentModal: { - id: 'app.settings.about.preview-privacy-consent-modal', - defaultMessage: 'Preview privacy & security modal', - }, }) const settings = ref(await getSettings()) @@ -127,9 +122,6 @@ watch( - diff --git a/apps/app-frontend/src/components/ui/settings/JavaSettings.vue b/apps/app-frontend/src/components/ui/settings/JavaSettings.vue index 9eb36c6..3623da6 100644 --- a/apps/app-frontend/src/components/ui/settings/JavaSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/JavaSettings.vue @@ -19,7 +19,6 @@ import MemoryAllocationDisplay from '@/components/ui/MemoryAllocationDisplay.vue import DownloadJavaModal from '@/components/ui/settings/DownloadJavaModal.vue' import InstalledJavaModal from '@/components/ui/settings/InstalledJavaModal.vue' import useMemorySlider from '@/composables/useMemorySlider' -import { trackEvent } from '@/helpers/analytics' import { collectGcContext } from '@/helpers/gc/context' import { wait_for_install_job } from '@/helpers/install' import { getJavaArgumentPresets } from '@/helpers/java-argument-presets' @@ -249,7 +248,6 @@ async function runScan(exhaustive) { scanning.value = true scanMode.value = 'quick' - trackEvent('JavaQuickScan', { source: 'settings' }) try { await find_filtered_jres(null, false, true, false).catch(handleError) } finally { @@ -262,7 +260,6 @@ async function confirmDeepScan() { showDeepScanConfirm.value = false scanning.value = true scanMode.value = 'deep' - trackEvent('JavaDeepScan', { source: 'settings' }) try { await find_filtered_jres(null, true, true, true).catch(handleError) } finally { @@ -280,7 +277,6 @@ async function handleManualAdd() { if (!javaInfo) return await set_java_version(javaInfo).catch(handleError) - trackEvent('JavaManualSelect', { path: filePath }) } async function onJavaDownloaded(job) { diff --git a/apps/app-frontend/src/components/ui/settings/PrivacySettings.vue b/apps/app-frontend/src/components/ui/settings/PrivacySettings.vue deleted file mode 100644 index b61293c..0000000 --- a/apps/app-frontend/src/components/ui/settings/PrivacySettings.vue +++ /dev/null @@ -1,156 +0,0 @@ - - - - - diff --git a/apps/app-frontend/src/components/ui/settings/settings-category-definitions.ts b/apps/app-frontend/src/components/ui/settings/settings-category-definitions.ts index ad7e766..25c2675 100644 --- a/apps/app-frontend/src/components/ui/settings/settings-category-definitions.ts +++ b/apps/app-frontend/src/components/ui/settings/settings-category-definitions.ts @@ -10,7 +10,6 @@ export type SettingsCategoryId = | 'content-downloads' | 'network-multiplayer' | 'storage-backups' - | 'privacy-data' | 'updates' | 'about' | 'feature-flags' @@ -106,15 +105,6 @@ export const settingsCategoryDefinitions: SettingsCategoryDefinition[] = [ group: 'data-privacy', onboardingId: 'settings-tab-storage-backups', }, - { - id: 'privacy-data', - name: defineMessage({ - id: 'app.settings.tabs.privacy-data', - defaultMessage: 'Privacy & data sharing', - }), - group: 'data-privacy', - onboardingId: 'settings-tab-privacy-data', - }, { id: 'updates', name: defineMessage({ id: 'app.settings.tabs.updates', defaultMessage: 'Updates' }), diff --git a/apps/app-frontend/src/components/ui/settings/settings-registry.ts b/apps/app-frontend/src/components/ui/settings/settings-registry.ts index c8ea6c8..67f9d3e 100644 --- a/apps/app-frontend/src/components/ui/settings/settings-registry.ts +++ b/apps/app-frontend/src/components/ui/settings/settings-registry.ts @@ -72,10 +72,6 @@ const categoryContent: Record import('./StorageBackupSettings.vue')), }, - 'privacy-data': { - icon: ShieldIcon, - content: defineAsyncComponent(() => import('./PrivacySettings.vue')), - }, updates: { icon: RefreshCwIcon, content: defineAsyncComponent(() => import('./UpdateSettings.vue')), diff --git a/apps/app-frontend/src/components/ui/settings/settings-search-index.ts b/apps/app-frontend/src/components/ui/settings/settings-search-index.ts index 3413c30..bfd5157 100644 --- a/apps/app-frontend/src/components/ui/settings/settings-search-index.ts +++ b/apps/app-frontend/src/components/ui/settings/settings-search-index.ts @@ -221,18 +221,6 @@ export const settingsSearchEntries: SettingsSearchEntry[] = [ label: message('app.crash-analysis.ai.settings.title', 'Crash AI explanation'), keywords: [message('app.settings.tabs.launch-defaults', 'Launch & instance defaults')], }, - { - id: 'privacy-telemetry', - categoryId: 'privacy-data', - targetId: 'settings-target-privacy-telemetry', - label: message('app.settings.privacy.telemetry', 'Telemetry'), - }, - { - id: 'privacy-discord-rpc', - categoryId: 'privacy-data', - targetId: 'settings-target-privacy-discord-rpc', - label: message('app.settings.privacy.discord-rpc', 'Discord rich presence'), - }, { id: 'java-installations', categoryId: 'java-performance', diff --git a/apps/app-frontend/src/components/ui/settings/settings-search.test.ts b/apps/app-frontend/src/components/ui/settings/settings-search.test.ts index b39fc50..57e1799 100644 --- a/apps/app-frontend/src/components/ui/settings/settings-search.test.ts +++ b/apps/app-frontend/src/components/ui/settings/settings-search.test.ts @@ -28,7 +28,6 @@ const settingsComponentFiles = { 'content-downloads': ['./AppearanceSettings.vue', './ResourceManagementSettings.vue'], 'network-multiplayer': ['./ResourceManagementSettings.vue', './MultiplayerSettings.vue'], 'storage-backups': ['./ResourceManagementSettings.vue', './StorageSettings.vue'], - 'privacy-data': ['./PrivacySettings.vue'], updates: ['./UpdateSettings.vue'], about: ['./AboutSettings.vue'], 'feature-flags': ['./FeatureFlagSettings.vue'], @@ -169,7 +168,7 @@ test('developer-only settings stay out of the normal search categories', () => { 'content-downloads', 'network-multiplayer', ]) - assert.deepEqual(categoriesForGroup('data-privacy'), ['storage-backups', 'privacy-data']) + assert.deepEqual(categoriesForGroup('data-privacy'), ['storage-backups']) assert.deepEqual(categoriesForGroup('support'), ['updates', 'about']) assert.deepEqual(categoriesForGroup('developer'), []) assert.deepEqual(categoriesForGroup('developer', true), ['feature-flags']) diff --git a/apps/app-frontend/src/components/ui/world/InstanceItem.vue b/apps/app-frontend/src/components/ui/world/InstanceItem.vue index bbf8693..6ab4e51 100644 --- a/apps/app-frontend/src/components/ui/world/InstanceItem.vue +++ b/apps/app-frontend/src/components/ui/world/InstanceItem.vue @@ -26,7 +26,6 @@ import { useRouter } from 'vue-router' import InstanceIcon from '@/components/ui/InstanceIcon.vue' import { useMinecraftLaunchError } from '@/composables/useMinecraftLaunchError' -import { trackEvent } from '@/helpers/analytics' import { get_project } from '@/helpers/cache' import { process_listener } from '@/helpers/events' import { kill, run } from '@/helpers/instance' @@ -108,11 +107,6 @@ const play = async (event: MouseEvent) => { if (!handled) handleSevereError(err, { instanceId: props.instance.id }) }) .finally(() => { - trackEvent('InstanceStart', { - loader: props.instance.loader, - game_version: props.instance.game_version, - source: 'InstanceItem', - }) }) emit('play') loading.value = false @@ -122,11 +116,6 @@ const stop = async (event: MouseEvent) => { event?.stopPropagation() loading.value = true await kill(props.instance.id).catch(handleError) - trackEvent('InstanceStop', { - loader: props.instance.loader, - game_version: props.instance.game_version, - source: 'InstanceItem', - }) emit('stop') loading.value = false } diff --git a/apps/app-frontend/src/composables/useDropImport.ts b/apps/app-frontend/src/composables/useDropImport.ts index 81384f1..fec1810 100644 --- a/apps/app-frontend/src/composables/useDropImport.ts +++ b/apps/app-frontend/src/composables/useDropImport.ts @@ -114,8 +114,6 @@ export interface DropImportOptions { onSchematicWorkshopPage: ComputedRef /** Check if path is a schematic file */ isSchematicFile: (path: string) => boolean - /** Track analytics event */ - trackEvent: (name: string, properties?: Record) => void /** Route to push */ router: Router } @@ -135,7 +133,6 @@ export interface DropImportOptions { * onSkinsPage, * onSchematicWorkshopPage, * isSchematicFile, - * trackEvent, * router, * route, * }) @@ -151,7 +148,6 @@ export function useDropImport(options: DropImportOptions) { onSkinsPage, onSchematicWorkshopPage, isSchematicFile, - trackEvent, router, } = options @@ -906,7 +902,6 @@ export function useDropImport(options: DropImportOptions) { clearDropProcessingNotification() await installModpackFromPath(filePath, fileName, { persistUntilDone: true }) - trackEvent('InstanceCreate', { source: 'DropConfirmModpack' }) await router.push('/library') return } diff --git a/apps/app-frontend/src/composables/useJavaTest.ts b/apps/app-frontend/src/composables/useJavaTest.ts index 1da8928..c7a910b 100644 --- a/apps/app-frontend/src/composables/useJavaTest.ts +++ b/apps/app-frontend/src/composables/useJavaTest.ts @@ -1,6 +1,5 @@ import { ref } from 'vue' -import { trackEvent } from '@/helpers/analytics' import { get_jre, test_jre } from '@/helpers/jre.js' export default function useJavaTest() { @@ -8,7 +7,7 @@ export default function useJavaTest() { const javaTestResult = ref(null) let testDebounceTimer: ReturnType | null = null - async function runJavaTest(path: string, version: number | null, track = true) { + async function runJavaTest(path: string, version: number | null) { if (testDebounceTimer) { clearTimeout(testDebounceTimer) testDebounceTimer = null @@ -28,10 +27,6 @@ export default function useJavaTest() { javaTestResult.value = false } testingJava.value = false - - if (track) { - trackEvent('JavaTest', { path, success: javaTestResult.value }) - } } function testJavaInstallationDebounced(path: string, version: number | null, delay = 600) { @@ -43,8 +38,8 @@ export default function useJavaTest() { testDebounceTimer = setTimeout(() => runJavaTest(path, version, false), delay) } - async function testJavaInstallation(path: string, version: number | null, track = false) { - await runJavaTest(path, version, track) + async function testJavaInstallation(path: string, version: number | null) { + await runJavaTest(path, version) } return { diff --git a/apps/app-frontend/src/helpers/analytics.ts b/apps/app-frontend/src/helpers/analytics.ts deleted file mode 100644 index cb5d011..0000000 --- a/apps/app-frontend/src/helpers/analytics.ts +++ /dev/null @@ -1,75 +0,0 @@ -interface InstanceProperties { - loader: string - game_version: string -} - -interface ProjectProperties extends InstanceProperties { - id: string - project_type: string -} - -type AnalyticsEventMap = { - Launched: { version: string; dev: boolean; onboarded: boolean } - PageView: { path: string; fromPath: string; failed: unknown } - InstanceCreate: { source: string } - InstanceCreateStart: { source: string } - InstanceStart: InstanceProperties & { source: string } - InstanceStop: Partial & { source?: string } - InstanceDuplicate: InstanceProperties - InstanceRepair: InstanceProperties - InstanceSetIcon: Record - InstanceRemoveIcon: Record - InstanceUpdateAll: InstanceProperties & { count: number; selected: boolean } - InstanceProjectUpdate: InstanceProperties & { id: string; name: string; project_type: string } - InstanceProjectDisable: InstanceProperties & { - id: string - name: string - project_type: string - disabled: boolean - } - InstanceProjectRemove: InstanceProperties & { id: string; name: string; project_type: string } - ProjectInstall: ProjectProperties & { version_id: string; title: string; source: string } - ProjectInstallStart: { source: string } - PackInstall: { id: string; version_id: string; title: string; source: string } - PackInstallStart: Record - AccountLogIn: { source?: string } - AccountLogOut: Record - JavaTest: { path: string; success: boolean } - JavaManualSelect: { version: string } - JavaAutoDetect: { path: string; version: string } - GalleryImageNext: { project_id: string; url: string } - GalleryImagePrevious: { project_id: string; url: unknown } - GalleryImageExpand: { project_id: string; url: string } -} - -export type AnalyticsEvent = keyof AnalyticsEventMap - -let optedIn = false -let debugEnabled = false - -export const initAnalytics = () => { - optedIn = true -} - -export const debugAnalytics = () => { - debugEnabled = true -} - -export const optOutAnalytics = () => { - optedIn = false -} - -export const optInAnalytics = () => { - optedIn = true -} - -type OptionalArgs = Record extends T ? [properties?: T] : [properties: T] - -export const trackEvent = ( - eventName: E, - ...args: OptionalArgs -) => { - if (optedIn && debugEnabled) { - console.debug('[Axolotl telemetry disabled]', eventName, args[0]) - } -} diff --git a/apps/app-frontend/src/helpers/instance.ts b/apps/app-frontend/src/helpers/instance.ts index 2bcab64..756120d 100644 --- a/apps/app-frontend/src/helpers/instance.ts +++ b/apps/app-frontend/src/helpers/instance.ts @@ -652,10 +652,6 @@ export async function update_project(instanceId: string, projectPath: string): P return await invoke('plugin:instance|instance_update_project', { instanceId, projectPath }) } -// Add a project to an instance from a version -// Returns a path to the new project file -export type DownloadReason = 'standalone' | 'dependency' | 'modpack' | 'update' - export interface ResolutionPreferences { game_versions?: string[] loaders?: string[] @@ -691,14 +687,10 @@ export interface ResolveContentPlan { export async function add_project_from_version( instanceId: string, versionId: string, - reason: DownloadReason, - dependentOnVersionId?: string, ): Promise { return await invoke('plugin:instance|instance_add_project_from_version', { instanceId, versionId, - reason, - dependentOnVersionId, }) } diff --git a/apps/app-frontend/src/helpers/settings.ts b/apps/app-frontend/src/helpers/settings.ts index 0ba448b..41ce5e7 100644 --- a/apps/app-frontend/src/helpers/settings.ts +++ b/apps/app-frontend/src/helpers/settings.ts @@ -175,9 +175,6 @@ export type AppSettings = { home_widgets: HomeDashboardConfig | null terracotta_public_nodes: string[] - telemetry: boolean - telemetry_consent_version: number - discord_rpc: boolean onboarded: boolean onboarding_version: number onboarding_instance_tour_completed: boolean @@ -207,12 +204,6 @@ export type AppSettings = { version: number } -export type PrivacySettings = { - telemetry: boolean - discord_rpc: boolean - consent_version: number -} - type LegacyMirrorSettings = { use_minecraft_mirror?: boolean use_modrinth_mirror?: boolean @@ -301,22 +292,6 @@ export async function cancel_directory_change(): Promise { return await invoke('plugin:settings|cancel_directory_change') } -export async function getPrivacySettings(): Promise { - return await invoke('plugin:settings|privacy_get') -} - -export async function savePrivacySettings(privacy: PrivacySettings): Promise { - return await invoke('plugin:settings|privacy_set', { privacy }) -} - -export async function setTelemetryEnabled(enabled: boolean): Promise { - return await invoke('plugin:settings|telemetry_set', { enabled }) -} - -export async function setDiscordRpcEnabled(enabled: boolean): Promise { - return await invoke('plugin:settings|discord_rpc_set', { enabled }) -} - export async function getProxyConfig(): Promise { return await invoke('plugin:settings|proxy_get') } diff --git a/apps/app-frontend/src/helpers/state.ts b/apps/app-frontend/src/helpers/state.ts index 3a81553..33711e7 100644 --- a/apps/app-frontend/src/helpers/state.ts +++ b/apps/app-frontend/src/helpers/state.ts @@ -44,10 +44,6 @@ export async function initialize_state() { return await invoke('initialize_state') } -export async function set_discord_activity(activity: string) { - return await invoke('set_discord_activity', { activity }) -} - // Gets active progress bars export async function progress_bars_list() { return await invoke>('plugin:utils|progress_bars_list') diff --git a/apps/app-frontend/src/helpers/telemetry.ts b/apps/app-frontend/src/helpers/telemetry.ts deleted file mode 100644 index 83356aa..0000000 --- a/apps/app-frontend/src/helpers/telemetry.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { invoke } from '@tauri-apps/api/core' - -export function installTelemetryHandlers(): void { - window.addEventListener('online', () => { - void invoke('plugin:telemetry|notify_online').catch(() => undefined) - }) -} diff --git a/apps/app-frontend/src/helpers/types.d.ts b/apps/app-frontend/src/helpers/types.d.ts index 0893fd8..4b06a48 100644 --- a/apps/app-frontend/src/helpers/types.d.ts +++ b/apps/app-frontend/src/helpers/types.d.ts @@ -216,8 +216,6 @@ type AppSettings = { close_behavior: 'ask' | 'close' | 'lightweight' home_widgets: import('@/components/home/home-dashboard').HomeDashboardConfig | null - telemetry: boolean - discord_rpc: boolean developer_mode: boolean onboarded: boolean diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json index 6ad79df..4d8f7c8 100644 --- a/apps/app-frontend/src/locales/en-US/index.json +++ b/apps/app-frontend/src/locales/en-US/index.json @@ -5912,12 +5912,6 @@ "app.onboarding.mascot-alt": { "message": "Starlight guide" }, - "app.onboarding.privacy.description": { - "message": "Manage anonymous telemetry, Discord Rich Presence, and the Minecraft log analysis service whenever you need to." - }, - "app.onboarding.privacy.title": { - "message": "Your data, your call" - }, "app.onboarding.resources.description": { "message": "Choose how content downloads and installs, from download sources to safety checks." }, @@ -5963,30 +5957,6 @@ "app.onboarding.welcome.title": { "message": "Everything is ready" }, - "app.privacy-consent.continue": { - "message": "Save and continue" - }, - "app.privacy-consent.discord-rpc": { - "message": "Discord Rich Presence" - }, - "app.privacy-consent.discord-rpc-description": { - "message": "Shows your current launcher or game activity in Discord when Discord is running." - }, - "app.privacy-consent.intro": { - "message": "Choose what Starlight may send or display. Nothing is sent until you confirm these choices." - }, - "app.privacy-consent.privacy-policy": { - "message": "Read the privacy policy" - }, - "app.privacy-consent.telemetry": { - "message": "Allow anonymous telemetry" - }, - "app.privacy-consent.telemetry-description": { - "message": "Helps count opted-in installations and daily active users. Full Minecraft logs and account credentials are never uploaded." - }, - "app.privacy-consent.title": { - "message": "Privacy & security" - }, "app.project.curseforge.loading": { "message": "Loading CurseForge project…" }, @@ -6806,9 +6776,6 @@ "app.settings.about.preview-minecraft-crash-modal": { "message": "Preview Minecraft crash window" }, - "app.settings.about.preview-privacy-consent-modal": { - "message": "Preview privacy & security modal" - }, "app.settings.about.product-title": { "message": "About {productName}" }, @@ -7070,21 +7037,6 @@ "app.settings.java.view-installed": { "message": "View installed Java" }, - "app.settings.privacy.data-handling": { - "message": "Telemetry uses a random installation identifier and sends only a daily activity signal. Turning telemetry off clears pending data immediately." - }, - "app.settings.privacy.discord-rpc": { - "message": "Discord Rich Presence" - }, - "app.settings.privacy.discord-rpc-description": { - "message": "Show your current launcher or game activity in Discord." - }, - "app.settings.privacy.telemetry": { - "message": "Allow telemetry" - }, - "app.settings.privacy.telemetry-description": { - "message": "Send one anonymous daily activity signal to improve usage statistics. Minecraft logs and account credentials are never uploaded." - }, "app.settings.resources.add-minecraft-directory": { "message": "Add .minecraft directory" }, @@ -7466,9 +7418,6 @@ "app.settings.tabs.network-multiplayer": { "message": "Network & multiplayer" }, - "app.settings.tabs.privacy-data": { - "message": "Privacy & data sharing" - }, "app.settings.tabs.storage": { "message": "Storage" }, diff --git a/apps/app-frontend/src/locales/zh-CN/index.json b/apps/app-frontend/src/locales/zh-CN/index.json index cfd65ef..4aeaafe 100644 --- a/apps/app-frontend/src/locales/zh-CN/index.json +++ b/apps/app-frontend/src/locales/zh-CN/index.json @@ -104,24 +104,42 @@ "app.easteregg.color-mine.revealed": { "message": "第 {row} 行,第 {column} 列,颜色 {color},周围同色 {number} 格" }, - "app.settings.developer.announcement-preview": { "message": "公告样式预览" }, + "app.settings.developer.announcement-preview": { + "message": "公告样式预览" + }, "app.settings.developer.announcement-preview-description": { "message": "使用本地示例预览真实公告组件,不请求远端公告,也不改变真实公告的已读状态。" }, - "app.settings.developer.preview-with-action": { "message": "显示可选的外部链接按钮" }, - "app.settings.developer.preview-announcement-modal": { "message": "预览启动弹窗" }, - "app.settings.developer.preview-announcement-popup": { "message": "预览 Popup 通知" }, - "app.remote-announcements.preview-title": { "message": "公告样式预览" }, + "app.settings.developer.preview-with-action": { + "message": "显示可选的外部链接按钮" + }, + "app.settings.developer.preview-announcement-modal": { + "message": "预览启动弹窗" + }, + "app.settings.developer.preview-announcement-popup": { + "message": "预览 Popup 通知" + }, + "app.remote-announcements.preview-title": { + "message": "公告样式预览" + }, "app.remote-announcements.preview-summary": { "message": "这是一条本地预览通知,点击“查看公告”可查看完整 Markdown 正文。" }, - "app.remote-announcements.preview-action": { "message": "访问官网" }, + "app.remote-announcements.preview-action": { + "message": "访问官网" + }, "app.remote-announcements.preview-content": { "message": "## 公告预览\n\n这是**示例正文**,不是已发布公告。\n\n- 支持标题、列表和链接\n- 默认自带关闭按钮\n\n> 预览不会影响真实公告的已读状态。\n\n| 类型 | 展示方式 |\n| --- | --- |\n| 启动弹窗 | 完整 Markdown 正文 |\n| Popup 通知 | 先显示摘要,再查看全文 |\n\n[访问官网](https://axlmc.org)" }, - "app.remote-announcements.view": { "message": "查看公告" }, - "app.remote-announcements.unread": { "message": "未读" }, - "app.remote-announcements.read-all": { "message": "将所有公告标为已读" }, + "app.remote-announcements.view": { + "message": "查看公告" + }, + "app.remote-announcements.unread": { + "message": "未读" + }, + "app.remote-announcements.read-all": { + "message": "将所有公告标为已读" + }, "app.account.signed-in-as": { "message": "登录身份:" }, @@ -5984,12 +6002,6 @@ "app.onboarding.mascot-alt": { "message": "引导吉祥物" }, - "app.onboarding.privacy.description": { - "message": "匿名遥测、Discord 活动状态与 Minecraft 日志分析服务都可以在这里调整。" - }, - "app.onboarding.privacy.title": { - "message": "你的数据,由你决定" - }, "app.onboarding.resources.description": { "message": "选择内容的下载与安装方式,包括下载源和安全确认。" }, @@ -6035,30 +6047,6 @@ "app.onboarding.welcome.title": { "message": "一切就绪" }, - "app.privacy-consent.continue": { - "message": "保存并继续" - }, - "app.privacy-consent.discord-rpc": { - "message": "Discord 活动状态" - }, - "app.privacy-consent.discord-rpc-description": { - "message": "Discord 运行时显示你当前使用启动器或游玩的状态。" - }, - "app.privacy-consent.intro": { - "message": "选择 Starlight 可以发送或展示的内容。确认前不会发送任何遥测。" - }, - "app.privacy-consent.privacy-policy": { - "message": "阅读隐私政策" - }, - "app.privacy-consent.telemetry": { - "message": "允许匿名遥测" - }, - "app.privacy-consent.telemetry-description": { - "message": "用于统计选择加入的安装量和每日活跃用户。绝不上传完整 Minecraft 日志或账户凭据。" - }, - "app.privacy-consent.title": { - "message": "隐私与安全" - }, "app.project.curseforge.loading": { "message": "正在加载 CurseForge 项目…" }, @@ -6851,9 +6839,6 @@ "app.settings.about.preview-minecraft-crash-modal": { "message": "预览 Minecraft 崩溃窗口" }, - "app.settings.about.preview-privacy-consent-modal": { - "message": "预览隐私与安全弹窗" - }, "app.settings.about.product-title": { "message": "关于 {productName}" }, @@ -7100,21 +7085,6 @@ "app.settings.java.view-installed": { "message": "查看已安装 Java" }, - "app.settings.privacy.data-handling": { - "message": "遥测使用随机安装标识,仅发送每日活跃信号。关闭遥测会立即清空待发送数据。" - }, - "app.settings.privacy.discord-rpc": { - "message": "Discord 活动状态" - }, - "app.settings.privacy.discord-rpc-description": { - "message": "在 Discord 中显示你当前使用启动器或游玩的状态。" - }, - "app.settings.privacy.telemetry": { - "message": "允许遥测" - }, - "app.settings.privacy.telemetry-description": { - "message": "发送匿名每日活跃信号以优化使用统计。绝不上传 Minecraft 日志或账户凭据。" - }, "app.settings.resources.app-cache": { "message": "应用缓存" }, @@ -7505,9 +7475,6 @@ "app.settings.tabs.network-multiplayer": { "message": "网络与多人游戏" }, - "app.settings.tabs.privacy-data": { - "message": "隐私与数据共享" - }, "app.settings.tabs.resource-management": { "message": "资源管理" }, @@ -10414,6 +10381,5 @@ }, "app.settings.about.easteregg.game-title": { "message": "彩蛋小游戏" - } } diff --git a/apps/app-frontend/src/locales/zh-TW/index.json b/apps/app-frontend/src/locales/zh-TW/index.json index 77af608..54cc3a6 100644 --- a/apps/app-frontend/src/locales/zh-TW/index.json +++ b/apps/app-frontend/src/locales/zh-TW/index.json @@ -5723,12 +5723,6 @@ "app.onboarding.mascot-alt": { "message": "引導吉祥物" }, - "app.onboarding.privacy.description": { - "message": "匿名遙測、Discord 活動狀態與 Minecraft 日誌分析服務都可以在這裡調整。" - }, - "app.onboarding.privacy.title": { - "message": "你的資料,由你決定" - }, "app.onboarding.resources.description": { "message": "調節下載、儲存和啟動器資源。給風扇一點尊嚴。" }, @@ -5774,30 +5768,6 @@ "app.onboarding.welcome.title": { "message": "一切就緒" }, - "app.privacy-consent.continue": { - "message": "儲存並繼續" - }, - "app.privacy-consent.discord-rpc": { - "message": "Discord 活動狀態" - }, - "app.privacy-consent.discord-rpc-description": { - "message": "Discord 執行時顯示你當前使用啟動器或遊玩的狀態。" - }, - "app.privacy-consent.intro": { - "message": "選擇 Starlight 可以傳送或展示的內容。確認前不會傳送任何遙測。" - }, - "app.privacy-consent.privacy-policy": { - "message": "閱讀隱私政策" - }, - "app.privacy-consent.telemetry": { - "message": "允許匿名遙測" - }, - "app.privacy-consent.telemetry-description": { - "message": "透過脫敏且限長的報告統計選擇加入的安裝量並排查啟動器錯誤。不會上傳完整 Minecraft 日誌或賬戶憑據。" - }, - "app.privacy-consent.title": { - "message": "隱私與安全" - }, "app.project.curseforge.loading": { "message": "正在載入 CurseForge 專案..." }, @@ -6566,9 +6536,6 @@ "app.settings.about.preview-minecraft-crash-modal": { "message": "預覽 Minecraft 崩潰窗口" }, - "app.settings.about.preview-privacy-consent-modal": { - "message": "預覽隱私與安全彈窗" - }, "app.settings.about.product-title": { "message": "關於 {productName}" }, @@ -6815,21 +6782,6 @@ "app.settings.java.view-installed": { "message": "查看已安裝 Java" }, - "app.settings.privacy.data-handling": { - "message": "遙測使用隨機安裝標識。錯誤上下文離開裝置前會經過脫敏和長度限制。關閉遙測會立即清空待傳送報告。" - }, - "app.settings.privacy.discord-rpc": { - "message": "Discord 活動狀態" - }, - "app.settings.privacy.discord-rpc-description": { - "message": "在 Discord 中顯示你當前使用啟動器或遊玩的狀態。" - }, - "app.settings.privacy.telemetry": { - "message": "允許遙測" - }, - "app.settings.privacy.telemetry-description": { - "message": "傳送匿名每日活躍訊號和脫敏的啟動器錯誤報告。絕不上傳 Minecraft 日誌或賬戶憑據。" - }, "app.settings.resources.app-cache": { "message": "應用程式快取" }, @@ -7220,9 +7172,6 @@ "app.settings.tabs.network-multiplayer": { "message": "網路與多人遊戲" }, - "app.settings.tabs.privacy-data": { - "message": "隱私與資料共享" - }, "app.settings.tabs.resource-management": { "message": "資源管理" }, diff --git a/apps/app-frontend/src/main.js b/apps/app-frontend/src/main.js index 6aa9b3d..4b85c37 100644 --- a/apps/app-frontend/src/main.js +++ b/apps/app-frontend/src/main.js @@ -9,7 +9,6 @@ import { createApp } from 'vue' import App from '@/App.vue' import { overlayScrollbarsDirective } from '@/directives/overlayScrollbars' -import { installTelemetryHandlers } from '@/helpers/telemetry' import i18nPlugin from '@/plugins/i18n' import i18nDebugPlugin from '@/plugins/i18n-debug' import router from '@/routes' @@ -18,8 +17,6 @@ const pinia = createPinia() const app = createApp(App) -installTelemetryHandlers() - app.use(VueQueryPlugin) app.use(router) app.use(pinia) diff --git a/apps/app-frontend/src/pages/Downloads.vue b/apps/app-frontend/src/pages/Downloads.vue index 7830eef..da46107 100644 --- a/apps/app-frontend/src/pages/Downloads.vue +++ b/apps/app-frontend/src/pages/Downloads.vue @@ -137,11 +137,11 @@
@@ -408,7 +388,6 @@ import { PlusIcon, ReportIcon, SearchIcon, - ServerIcon, SpinnerIcon, StopCircleIcon, } from '@modrinth/assets' @@ -424,7 +403,6 @@ import { getLatestMatchingInstallVersion, getTargetInstallPreferences, injectNotificationManager, - injectPopupNotificationManager, NavTabs, OverflowMenu, ProjectBackgroundGradient, @@ -501,7 +479,6 @@ import UpgradeProjectReturnBar from './UpgradeProjectReturnBar.vue' dayjs.extend(relativeTime) const { addNotification, handleError } = injectNotificationManager() -const popupNotificationManager = injectPopupNotificationManager() const { install: installVersion } = injectContentInstall() const contentSelection = injectContentSelection() const route = useRoute() @@ -603,22 +580,6 @@ const messages = defineMessages({ id: 'project.actions.view-modpacks', defaultMessage: 'View modpacks', }, - startServer: { - id: 'app.project.modpack-server.start', - defaultMessage: 'Start server', - }, - serverCreated: { - id: 'app.project.modpack-server.created-title', - defaultMessage: 'Server created', - }, - serverCreatedDescription: { - id: 'app.project.modpack-server.created-description', - defaultMessage: '{name} is ready. Configure and start it in Multiplayer.', - }, - openServer: { - id: 'app.project.modpack-server.open', - defaultMessage: 'Open server', - }, }) const { installingServerProjects, playServerProject, showAddServerToInstanceModal } = @@ -642,15 +603,6 @@ const favoriteSaved = computed(() => data.value ? contentFavorites.isFavorite('modrinth', data.value.id) : false, ) -const serverCapableModpack = computed( - () => data.value?.project_type === 'modpack' && data.value.server_side !== 'unsupported', -) - -async function openModpackServerFlow() { - // 服务器创建弹窗(CreateModpackServerModal)已在上游移除,此流程暂不可用。 - // 如需恢复:重新实现该组件,并在此处调用其 show() 方法。 -} - async function toggleFavorite() { if (!data.value || !favoriteSupported.value || favoritePending.value) return await contentFavorites diff --git a/apps/app-frontend/src/pages/project/Versions.vue b/apps/app-frontend/src/pages/project/Versions.vue index cfd3217..6f230fe 100644 --- a/apps/app-frontend/src/pages/project/Versions.vue +++ b/apps/app-frontend/src/pages/project/Versions.vue @@ -30,16 +30,6 @@ - props.project?.project_type === 'modpack' && props.project?.server_side !== 'unsupported', -) - const { handleError } = injectNotificationManager() const route = useRoute() diff --git a/apps/app-frontend/src/providers/content-install.ts b/apps/app-frontend/src/providers/content-install.ts index c1ed47a..412edcd 100644 --- a/apps/app-frontend/src/providers/content-install.ts +++ b/apps/app-frontend/src/providers/content-install.ts @@ -15,7 +15,6 @@ import type { Router } from 'vue-router' import type ContentInstallPreviewModal from '@/components/ui/ContentInstallPreviewModal.vue' import type { ContentInstallPreviewData } from '@/components/ui/ContentInstallPreviewModal.vue' import type { ModpackInstallModalData } from '@/components/ui/modal/ModpackInstallModal.vue' -import { trackEvent } from '@/helpers/analytics' import { get_organization, get_project, @@ -868,12 +867,6 @@ export function createContentInstall(opts: { }) removeInstallingItems(createdInstanceId, [project.id]) markInstanceContentChanged(createdInstanceId) - trackEvent('PackInstall', { - id: project.id, - version_id: version.id, - title: project.title, - source, - }) callback(version.id, [project.id]) } catch (err) { debugState('createAndInstallCurseForgeModpack ERR', { err: String(err), createdInstanceId }) @@ -997,7 +990,6 @@ export function createContentInstall(opts: { if (sessionId !== currentSessionId) return contentInstallModalOpen = true modalRef?.show() - trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' }) } get_game_versions() @@ -1068,7 +1060,6 @@ export function createContentInstall(opts: { await nextTick() contentInstallModalOpen = true modalRef?.show() - trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' }) return sessionId } @@ -1688,15 +1679,6 @@ export function createContentInstall(opts: { if (storeInstance) storeInstance.installing = true try { await queueCurrentCurseForgeWorld(selectedInstance) - trackEvent('ProjectInstall', { - loader: selectedInstance.loader, - game_version: selectedInstance.game_version, - id: currentProject.id, - version_id: currentWorldFileId ?? '', - project_type: 'world', - title: currentProject.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(currentWorldFileId ?? undefined, [currentProject.id]) hideContentInstallModal() } catch (err) { @@ -1758,15 +1740,6 @@ export function createContentInstall(opts: { { ...request, excluded_project_ids: excludedProjectIds }, { title: currentProject.title, iconUrl: currentProject.icon_url }, ) - trackEvent('ProjectInstall', { - loader: selectedInstance.loader, - game_version: selectedInstance.game_version, - id: currentProject.id, - version_id: version.id, - project_type: currentProject.project_type, - title: currentProject.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(version.id, [currentProject.id]) hideContentInstallModal() } catch (err) { @@ -1786,15 +1759,6 @@ export function createContentInstall(opts: { settleCurrentCallback() return } - trackEvent('ProjectInstall', { - loader: selectedInstance.loader, - game_version: selectedInstance.game_version, - id: currentProject.id, - version_id: version.id, - project_type: currentProject.project_type, - title: currentProject.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(version.id, [currentProject.id]) hideContentInstallModal() } catch (err) { @@ -1830,15 +1794,6 @@ export function createContentInstall(opts: { storeInstance.installed = primaryInstalled storeInstance.installing = false } - trackEvent('ProjectInstall', { - loader: selectedInstance.loader, - game_version: selectedInstance.game_version, - id: currentProject!.id, - version_id: version.id, - project_type: currentProject!.project_type, - title: currentProject!.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(primaryInstalled ? version.id : undefined, installedProjectIds) } catch (err) { if (storeInstance) storeInstance.installing = false @@ -1878,7 +1833,6 @@ export function createContentInstall(opts: { await nextTick() incompatibilityWarningModalRef?.show(version.id) - trackEvent('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' }) } async function handleIncompatibilityWarningInstall(version: Labrinth.Versions.v2.Version) { @@ -1931,15 +1885,6 @@ export function createContentInstall(opts: { incompatibilityWarningModalRef?.hide() removeInstallingItems(instance.id, [project.id]) - trackEvent('ProjectInstall', { - loader: instance.loader ?? '', - game_version: instance.game_version ?? '', - id: project.id, - version_id: version.id, - project_type: project.project_type, - title: project.title, - source: 'ProjectIncompatibilityWarningModal', - }) } function handleIncompatibilityWarningCancel() { @@ -2056,16 +2001,6 @@ export function createContentInstall(opts: { }, { title: currentProject!.title, iconUrl: currentProject!.icon_url }, ) - trackEvent('InstanceCreate', { source: 'ProjectInstallModal' }) - trackEvent('ProjectInstall', { - loader: data.loader, - game_version: data.gameVersion, - id: currentProject!.id, - version_id: version.id, - project_type: currentProject!.project_type, - title: currentProject!.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(version.id, [currentProject!.id]) hideContentInstallModal() return @@ -2085,16 +2020,6 @@ export function createContentInstall(opts: { excludedCurseForgeProjectIds, ) if (!job) return - trackEvent('InstanceCreate', { source: 'ProjectInstallModal' }) - trackEvent('ProjectInstall', { - loader: data.loader, - game_version: data.gameVersion, - id: currentProject!.id, - version_id: version.id, - project_type: currentProject!.project_type, - title: currentProject!.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(version.id, [currentProject!.id]) hideContentInstallModal() return @@ -2131,18 +2056,6 @@ export function createContentInstall(opts: { : `/instance/${encodeURIComponent(id)}`, ) - trackEvent('InstanceCreate', { - source: 'ProjectInstallModal', - }) - trackEvent('ProjectInstall', { - loader: data.loader, - game_version: data.gameVersion, - id: currentProject!.id, - version_id: version.id, - project_type: currentProject!.project_type, - title: currentProject!.title, - source: 'ProjectInstallModal', - }) settleCurrentCallback(version.id, installedProjectIds) modalRef?.hide() @@ -2282,15 +2195,6 @@ export function createContentInstall(opts: { { ...installRequest, excluded_project_ids: excludedProjectIds }, { title: project.title, iconUrl: project.icon_url }, ) - trackEvent('ProjectInstall', { - loader: instance.loader, - game_version: instance.game_version, - id: project.id, - project_type: project.project_type, - version_id: version.id, - title: project.title, - source, - }) callback(version.id, [project.id]) } else { await showIncompatibilityWarning(instance, project, projectVersions, version, callback) @@ -2402,15 +2306,6 @@ export function createContentInstall(opts: { if (isVersionCompatible(version, project, instance)) { const job = await queueCurrentCurseForgeVersion(instance, project, version) if (!job) return - trackEvent('ProjectInstall', { - loader: instance.loader, - game_version: instance.game_version, - id: project.id, - project_type: project.project_type, - version_id: version.id, - title: project.title, - source, - }) callback(version.id, [project.id]) } else { await showIncompatibilityWarning(instance, project, versions, version, callback) @@ -2457,7 +2352,6 @@ export function createContentInstall(opts: { if (sessionId !== currentSessionId) return contentInstallModalOpen = true modalRef?.show() - trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' }) try { const candidates = (await list()).filter( @@ -2537,15 +2431,6 @@ export function createContentInstall(opts: { const instance = await get(instanceId) if (!instance) throw new Error(formatMessage(curseForgeWorldUnknownInstanceMessage)) await queueCurrentCurseForgeWorld(instance) - trackEvent('ProjectInstall', { - loader: instance.loader, - game_version: instance.game_version, - id: currentProject!.id, - version_id: file.id.toString(), - project_type: 'world', - title: currentProject!.title, - source, - }) callback(file.id.toString(), [currentProject!.id]) } @@ -2700,12 +2585,6 @@ export function createContentInstall(opts: { if (instanceId) { createInstanceCallback(instanceId) } - trackEvent('PackInstall', { - id: project.id, - version_id: versionId, - title: project.title, - source, - }) callback(versionId) }, handleModpackInstallCancel() { diff --git a/apps/app-frontend/src/providers/server-install.ts b/apps/app-frontend/src/providers/server-install.ts index fdcfc37..07b2a92 100644 --- a/apps/app-frontend/src/providers/server-install.ts +++ b/apps/app-frontend/src/providers/server-install.ts @@ -4,7 +4,6 @@ import { createContext } from '@modrinth/ui' import { type Ref, ref } from 'vue' import type { Router } from 'vue-router' -import { trackEvent } from '@/helpers/analytics' import { get_project, get_project_v3, get_version } from '@/helpers/cache.js' import { install_create_instance, @@ -163,11 +162,6 @@ export function createServerInstall(opts: { action: async () => { try { await joinServer(project.id, serverAddress) - trackEvent('InstanceStart', { - loader: project.loader, - game_version: project.game_version, - source: 'ServerProject', - }) } catch (err) { handleSevereError(err, { instanceId: project.id }) } @@ -198,11 +192,6 @@ export function createServerInstall(opts: { action: async () => { try { if (serverAddress) await start_join_server(instance.id, serverAddress) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'ServerProject', - }) } catch (err) { handleSevereError(err, { instanceId: instance.id }) } @@ -348,11 +337,6 @@ export function createServerInstall(opts: { // Join server try { await joinServer(instance.id, serverAddress) - trackEvent('InstanceStart', { - loader: instance.loader, - game_version: instance.game_version, - source: 'ServerProject', - }) } catch (err) { handleSevereError(err, { instanceId: instance.id }) } diff --git a/apps/app-frontend/src/providers/setup/creation-modal.ts b/apps/app-frontend/src/providers/setup/creation-modal.ts index 11eedc4..bba1772 100644 --- a/apps/app-frontend/src/providers/setup/creation-modal.ts +++ b/apps/app-frontend/src/providers/setup/creation-modal.ts @@ -13,7 +13,6 @@ import { useRouter } from 'vue-router' import type UnknownPackWarningModal from '@/components/ui/install_flow/UnknownPackWarningModal.vue' import type ModpackAlreadyInstalledModal from '@/components/ui/modal/ModpackAlreadyInstalledModal.vue' -import { trackEvent } from '@/helpers/analytics' import { get_project_versions, get_search_results } from '@/helpers/cache.js' import { getCurseForgeFiles, hasCompatibleCurseForgeFile } from '@/helpers/curseforge' import { install_job_listener } from '@/helpers/events.js' @@ -143,7 +142,6 @@ export function setupCreationModal( }, { name }, ).catch(handleError) - trackEvent('InstanceCreate', { source: 'CreationModalModpack' }) } async function handleCreate(config: CreationFlowContextValue) { @@ -222,7 +220,6 @@ export function setupCreationModal( handleError(error) } } - trackEvent('InstanceCreate', { source: 'CreationModalImport' }) return } @@ -238,7 +235,6 @@ export function setupCreationModal( const splitPath = config.modpackFilePath.value.split(/[\\/]/) const fileName = splitPath ? splitPath[splitPath.length - 1] : config.modpackFilePath.value await installModpackFromPath(config.modpackFilePath.value, fileName) - trackEvent('InstanceCreate', { source: 'CreationModalModpackFile' }) return } @@ -281,9 +277,6 @@ export function setupCreationModal( gameDirOverride, }).catch(handleError) - trackEvent('InstanceCreate', { - source: 'CreationModal', - }) } catch (err) { handleError(err as Error) } diff --git a/apps/app/build.rs b/apps/app/build.rs index 3a3d76e..18a4e1c 100644 --- a/apps/app/build.rs +++ b/apps/app/build.rs @@ -509,10 +509,6 @@ fn main() { .commands(&[ "settings_get", "settings_set", - "privacy_get", - "privacy_set", - "telemetry_set", - "discord_rpc_set", "download_engine_set", "cancel_directory_change", "proxy_get", diff --git a/apps/app/src/api/instance.rs b/apps/app/src/api/instance.rs index c647674..99d41a1 100644 --- a/apps/app/src/api/instance.rs +++ b/apps/app/src/api/instance.rs @@ -6,7 +6,6 @@ use path_util::SafeRelativeUtf8UnixPathBuf; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; -use theseus::DownloadReason; use theseus::data::{ AppliedContentSetPatch, ContentItem, Dependency, EditInstance as CoreEditInstance, InstanceInstallCandidate, @@ -1116,16 +1115,11 @@ pub async fn instance_update_project( pub async fn instance_add_project_from_version( instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, ) -> Result { - Ok(theseus::instance::add_project_from_version( - instance_id, - version_id, - reason, - dependent_on_version_id, + Ok( + theseus::instance::add_project_from_version(instance_id, version_id) + .await?, ) - .await?) } #[tauri::command] diff --git a/apps/app/src/api/mod.rs b/apps/app/src/api/mod.rs index d2e10f9..544509a 100644 --- a/apps/app/src/api/mod.rs +++ b/apps/app/src/api/mod.rs @@ -25,7 +25,6 @@ pub mod shortcuts; pub mod storage; pub mod system_accent; pub mod tags; -pub mod telemetry; pub mod terracotta; pub mod translation; pub mod utils; diff --git a/apps/app/src/api/settings.rs b/apps/app/src/api/settings.rs index ea3c12f..902632d 100644 --- a/apps/app/src/api/settings.rs +++ b/apps/app/src/api/settings.rs @@ -8,10 +8,6 @@ pub fn init() -> tauri::plugin::TauriPlugin { .invoke_handler(tauri::generate_handler![ settings_get, settings_set, - privacy_get, - privacy_set, - telemetry_set, - discord_rpc_set, download_engine_set, cancel_directory_change, proxy_get, @@ -41,26 +37,6 @@ pub async fn settings_set( Ok(()) } -#[tauri::command] -pub async fn privacy_get() -> Result { - Ok(settings::get_privacy().await?) -} - -#[tauri::command] -pub async fn privacy_set(privacy: PrivacySettings) -> Result { - Ok(settings::set_privacy(privacy).await?) -} - -#[tauri::command] -pub async fn telemetry_set(enabled: bool) -> Result { - Ok(settings::set_telemetry(enabled).await?) -} - -#[tauri::command] -pub async fn discord_rpc_set(enabled: bool) -> Result { - Ok(settings::set_discord_rpc(enabled).await?) -} - #[tauri::command] pub async fn download_engine_set( engine: settings::DownloadEngine, diff --git a/apps/app/src/api/telemetry.rs b/apps/app/src/api/telemetry.rs deleted file mode 100644 index 754be4c..0000000 --- a/apps/app/src/api/telemetry.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn init() -> tauri::plugin::TauriPlugin { - tauri::plugin::Builder::new("telemetry") - .invoke_handler(tauri::generate_handler![notify_online,]) - .build() -} - -#[tauri::command] -pub fn notify_online() { - theseus::telemetry::notify_online(); -} diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index 5bef442..f537deb 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -389,16 +389,6 @@ async fn backup_app_db_for_update( Ok(()) } -#[tauri::command] -async fn set_discord_activity(activity: String) -> api::Result<()> { - let state = State::get().await?; - state - .discord_rpc - .set_launcher_activity(&activity, true) - .await?; - Ok(()) -} - // Should be call once Vue has mounted the app #[tracing::instrument(skip_all)] #[tauri::command] @@ -823,7 +813,6 @@ fn main() { .plugin(api::schematic_preview::init()) .plugin(api::shortcuts::init()) .plugin(api::tags::init()) - .plugin(api::telemetry::init()) .plugin(api::translation::init()) .plugin(api::utils::init()) .plugin(api::cache::init()) @@ -851,7 +840,6 @@ fn main() { copy_database_between_channels, beta_database_exists, backup_app_db_for_update, - set_discord_activity, is_dev, portable::is_portable_mode, are_updates_enabled, diff --git a/apps/telemetry-dashboard/.dev.vars.example b/apps/telemetry-dashboard/.dev.vars.example deleted file mode 100644 index 15722d7..0000000 --- a/apps/telemetry-dashboard/.dev.vars.example +++ /dev/null @@ -1,9 +0,0 @@ -# Fictional local values only. Never commit a real Access token or audience. -TELEMETRY_ADMIN_MOCK_AUTH=true -TELEMETRY_ADMIN_MOCK_SCENARIO=normal -NUXT_ACCESS_TEAM_DOMAIN=example -NUXT_ACCESS_AUDIENCE=fixture-audience - -# Cloudflare GraphQL Analytics API (system page account usage check, local dev only) -# CLOUDFLARE_ACCOUNT_ID= -# CLOUDFLARE_ANALYTICS_TOKEN= diff --git a/apps/telemetry-dashboard/.gitignore b/apps/telemetry-dashboard/.gitignore deleted file mode 100644 index 245259b..0000000 --- a/apps/telemetry-dashboard/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vercel -.env* diff --git a/apps/telemetry-dashboard/.prettierignore b/apps/telemetry-dashboard/.prettierignore deleted file mode 100644 index fcd57ca..0000000 --- a/apps/telemetry-dashboard/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -.nuxt/ -.output/ -.wrangler/ -node_modules/ -coverage/ diff --git a/apps/telemetry-dashboard/README.md b/apps/telemetry-dashboard/README.md deleted file mode 100644 index ff3ad30..0000000 --- a/apps/telemetry-dashboard/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# Starlight Telemetry Dashboard - -Read-only administration UI for the existing `axolotl-telemetry` D1 database and -`axolotl-telemetry-errors` R2 bucket. It does not share routes or code with the public telemetry -collector. - -## Local development - -Mock authentication is accepted only when `NODE_ENV=development` and -`TELEMETRY_ADMIN_MOCK_AUTH=true` are both present. - -Use the production D1 and R2 resources through Wrangler remote bindings while keeping authentication -local to the development server: - -```powershell -$env:TELEMETRY_ADMIN_MOCK_AUTH='true' -$env:TELEMETRY_ADMIN_REMOTE_BINDINGS='true' -pnpm --filter @axolotl/telemetry-dashboard dev -``` - -Remote mode is read-only at the application layer: the Admin API issues only `SELECT` statements -and a single registered-object R2 `GET`. It never exposes Cloudflare credentials to the browser. - -For deterministic fixture scenarios, leave `TELEMETRY_ADMIN_REMOTE_BINDINGS` unset: - -```powershell -$env:TELEMETRY_ADMIN_MOCK_AUTH='true' -$env:TELEMETRY_ADMIN_MOCK_SCENARIO='normal' -pnpm --filter @axolotl/telemetry-dashboard dev -``` - -Supported deterministic scenarios are `normal`, `empty`, `api-error`, `no-sample`, -`budget-reached`, `unconfigured-auth`, and `forbidden`. All mock values are synthetic fixtures. - -## Production deployment (Cloudflare Workers) - -The dashboard runs on the `axolotl-telemetry-dashboard` Worker with the custom domain -`admin.axlmc.org`. It uses the native D1 and R2 bindings declared in `wrangler.toml`; no data -credentials are sent to the browser. - -Do not deploy the dashboard until every item below is complete: - -1. Create a GitHub OAuth App controlled by the `Axolotl-Launcher` organization. Use - `https://admin.axlmc.org` as its homepage and the callback URL shown by Cloudflare Zero Trust, - normally `https://.cloudflareaccess.com/cdn-cgi/access/callback`. -2. Add GitHub as a Cloudflare Zero Trust identity provider using that Client ID and Client Secret. - Keep the Client Secret only in GitHub and Cloudflare. -3. Create a self-hosted Access application for `admin.axlmc.org` with an 8-hour session duration. -4. Create one Allow policy with `Include -> GitHub Organization -> Axolotl-Launcher`. Do not add a - bypass policy or a broader include rule. -5. Keep the Worker custom domain `admin.axlmc.org` bound to `axolotl-telemetry-dashboard`. The DNS - records for `axlmc.org` stay proxied through Cloudflare. - -Build and deploy from `apps/telemetry-dashboard`: - -```powershell -pnpm --filter @axolotl/telemetry-dashboard build -pnpm --filter @axolotl/telemetry-dashboard exec wrangler deploy -``` - -`nuxi build` uses Nitro's `cloudflare-module` preset by default and emits -`.output/server/index.mjs` plus `.output/public`, exactly what `wrangler.toml` references. - -### Automatic deployment - -`.github/workflows/deploy-telemetry-dashboard.yml` deploys on every push to `main` that touches -`apps/telemetry-dashboard/**`, and can also be triggered manually. It requires one repository -secret: - -- `CLOUDFLARE_API_TOKEN`: an API token with Workers Scripts Edit and Workers Routes Edit - permission for the account that owns `axolotl-telemetry-dashboard`. - -Do not add `[skip ci]` to commits that should reach production: GitHub Actions skips all workflows -for such commits, including this deployment. - -### Cloudflare account usage check - -The system page reports account-wide Workers, D1, and R2 usage through the GraphQL Analytics API. -Enable it once with two Worker secrets; secrets survive CI deploys because they live on the Worker, -not in the repository: - -1. Create an API token at `dash.cloudflare.com` → My Profile → API Tokens with the - `Account Analytics: Read` permission for the account that owns the telemetry resources. -2. From `apps/telemetry-dashboard`, run - `pnpm exec wrangler secret put CLOUDFLARE_ANALYTICS_TOKEN` and paste that token. -3. Run `pnpm exec wrangler secret put CLOUDFLARE_ACCOUNT_ID` and paste the 32-character account ID. - -The check stays fail-closed: without both values the row reports 尚未配置, and any dataset failure -only degrades the row. The token is used server-side for three read-only GraphQL queries per system -page load (Workers invocations 24h, D1 rows today, R2 operations 30d) and is never sent to the -browser. - -### Unused Vercel target - -An earlier Vercel project (`axolotl-telemetry-dashboard`) exists, but its `admin.axlmc.org` domain -was never pointed at Vercel and traffic is served by the Cloudflare Worker. The Nitro `vercel` -preset and `server/utils/vercel-data-source.ts` remain as an offline fallback and are not part of -the production path. Do not enable both targets for the same hostname. - -Verify an unauthenticated request is intercepted by Cloudflare Access, then verify -`/api/admin/session` reports `dataSource: production` after authentication. - -The server fails closed when Access or the remote data source configuration is absent. A production -build ignores the mock provider even if a mock environment variable is present. All Admin API D1 -operations are restricted to `SELECT`/`WITH` queries, and R2 reads require an object key previously -registered in D1. diff --git a/apps/telemetry-dashboard/app.vue b/apps/telemetry-dashboard/app.vue deleted file mode 100644 index c80dcc9..0000000 --- a/apps/telemetry-dashboard/app.vue +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/apps/telemetry-dashboard/assets/styles/tailwind.css b/apps/telemetry-dashboard/assets/styles/tailwind.css deleted file mode 100644 index 52fd770..0000000 --- a/apps/telemetry-dashboard/assets/styles/tailwind.css +++ /dev/null @@ -1,162 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - --background: 210 18% 97%; - --foreground: 220 20% 11%; - --card: 0 0% 100%; - --card-foreground: 220 18% 12%; - --popover: 0 0% 100%; - --popover-foreground: 220 18% 12%; - --primary: 164 64% 27%; - --primary-foreground: 0 0% 100%; - --secondary: 210 16% 93%; - --secondary-foreground: 220 16% 18%; - --muted: 210 16% 94%; - --muted-foreground: 215 12% 43%; - --accent: 38 92% 52%; - --accent-foreground: 30 30% 12%; - --destructive: 0 72% 48%; - --destructive-foreground: 0 0% 100%; - --border: 214 16% 86%; - --input: 214 16% 78%; - --ring: 164 64% 27%; - --surface-1: 210 18% 97%; - --surface-2: 0 0% 100%; - --surface-3: 210 17% 94%; - --surface-4: 214 16% 86%; - --surface-5: 214 15% 72%; - --chart-green: #17845f; - --chart-gold: #d19213; - --chart-coral: #d85d4a; - --chart-cyan: #278ba8; - } - - .dark { - --background: 220 16% 8%; - --foreground: 210 16% 92%; - --card: 220 15% 12%; - --card-foreground: 210 16% 92%; - --popover: 220 16% 12%; - --popover-foreground: 210 16% 92%; - --primary: 160 54% 48%; - --primary-foreground: 220 18% 8%; - --secondary: 218 14% 17%; - --secondary-foreground: 210 16% 90%; - --muted: 218 14% 16%; - --muted-foreground: 215 12% 64%; - --accent: 40 88% 56%; - --accent-foreground: 30 32% 10%; - --destructive: 0 62% 51%; - --destructive-foreground: 0 0% 100%; - --border: 218 13% 23%; - --input: 218 13% 27%; - --ring: 160 54% 48%; - --surface-1: 220 16% 8%; - --surface-2: 220 15% 11%; - --surface-3: 218 14% 15%; - --surface-4: 218 13% 23%; - --surface-5: 216 12% 34%; - --chart-green: #40c995; - --chart-gold: #e6ad3e; - --chart-coral: #ef7b68; - --chart-cyan: #52b6d0; - } - - * { - @apply border-border; - } - - html, - body, - #__nuxt { - @apply min-h-full; - } - - body { - @apply m-0 overflow-x-hidden bg-surface-1 font-sans text-foreground antialiased; - letter-spacing: 0; - } - - button, - input, - select { - letter-spacing: 0; - } -} - -@layer utilities { - .tabular-nums { - font-variant-numeric: tabular-nums; - } -} - -.dashboard-page-enter-active, -.dashboard-page-leave-active { - transition: - opacity 160ms ease, - transform 160ms ease; -} - -.dashboard-page-enter-from { - opacity: 0; - transform: translateY(4px); -} - -.dashboard-page-leave-to { - opacity: 0; - transform: translateY(-2px); -} - -.fade-enter-active, -.fade-leave-active { - transition: opacity 160ms ease; -} - -.fade-enter-from, -.fade-leave-to { - opacity: 0; -} - -.sheet-overlay[data-state='open'] { - animation: overlay-in 180ms ease-out; -} - -.sheet-panel[data-state='open'] { - animation: sheet-in 220ms cubic-bezier(0.22, 1, 0.36, 1); -} - -@keyframes overlay-in { - from { - opacity: 0; - } -} - -@keyframes sheet-in { - from { - transform: translateX(20px); - opacity: 0; - } -} - -@media (prefers-reduced-motion: reduce) { - .dashboard-page-enter-active, - .dashboard-page-leave-active, - .sheet-overlay[data-state='open'], - .sheet-panel[data-state='open'] { - animation: none; - transition: none; - } -} - -.unovis-xy-container text { - fill: hsl(var(--muted-foreground)); - font-size: 11px; -} - -.unovis-xy-container .axis line, -.unovis-xy-container .axis path { - stroke: hsl(var(--surface-4)); -} diff --git a/apps/telemetry-dashboard/components.json b/apps/telemetry-dashboard/components.json deleted file mode 100644 index 6d6a4f9..0000000 --- a/apps/telemetry-dashboard/components.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://shadcn-vue.com/schema.json", - "style": "new-york", - "typescript": true, - "tailwind": { - "config": "tailwind.config.ts", - "css": "assets/styles/tailwind.css", - "baseColor": "zinc", - "cssVariables": true - }, - "aliases": { - "components": "~/components", - "utils": "~/lib/utils", - "ui": "~/components/ui" - } -} diff --git a/apps/telemetry-dashboard/components/AppState.vue b/apps/telemetry-dashboard/components/AppState.vue deleted file mode 100644 index 57c6028..0000000 --- a/apps/telemetry-dashboard/components/AppState.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/MetricCard.vue b/apps/telemetry-dashboard/components/MetricCard.vue deleted file mode 100644 index 082cf74..0000000 --- a/apps/telemetry-dashboard/components/MetricCard.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/PageHeader.vue b/apps/telemetry-dashboard/components/PageHeader.vue deleted file mode 100644 index 8546ee4..0000000 --- a/apps/telemetry-dashboard/components/PageHeader.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/charts/DistributionChart.vue b/apps/telemetry-dashboard/components/charts/DistributionChart.vue deleted file mode 100644 index b3b04bd..0000000 --- a/apps/telemetry-dashboard/components/charts/DistributionChart.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/charts/TrendChart.vue b/apps/telemetry-dashboard/components/charts/TrendChart.vue deleted file mode 100644 index 8ff12ea..0000000 --- a/apps/telemetry-dashboard/components/charts/TrendChart.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/system/StatusRow.vue b/apps/telemetry-dashboard/components/system/StatusRow.vue deleted file mode 100644 index 07779ab..0000000 --- a/apps/telemetry-dashboard/components/system/StatusRow.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Alert.vue b/apps/telemetry-dashboard/components/ui/Alert.vue deleted file mode 100644 index 3bebc3d..0000000 --- a/apps/telemetry-dashboard/components/ui/Alert.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Badge.vue b/apps/telemetry-dashboard/components/ui/Badge.vue deleted file mode 100644 index eec2761..0000000 --- a/apps/telemetry-dashboard/components/ui/Badge.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Button.vue b/apps/telemetry-dashboard/components/ui/Button.vue deleted file mode 100644 index cf95e9e..0000000 --- a/apps/telemetry-dashboard/components/ui/Button.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Card.vue b/apps/telemetry-dashboard/components/ui/Card.vue deleted file mode 100644 index 8d638d0..0000000 --- a/apps/telemetry-dashboard/components/ui/Card.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Command.vue b/apps/telemetry-dashboard/components/ui/Command.vue deleted file mode 100644 index ae3a0f8..0000000 --- a/apps/telemetry-dashboard/components/ui/Command.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/DropdownMenu.vue b/apps/telemetry-dashboard/components/ui/DropdownMenu.vue deleted file mode 100644 index 3dba603..0000000 --- a/apps/telemetry-dashboard/components/ui/DropdownMenu.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Select.vue b/apps/telemetry-dashboard/components/ui/Select.vue deleted file mode 100644 index 25efa58..0000000 --- a/apps/telemetry-dashboard/components/ui/Select.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Sheet.vue b/apps/telemetry-dashboard/components/ui/Sheet.vue deleted file mode 100644 index 8335f93..0000000 --- a/apps/telemetry-dashboard/components/ui/Sheet.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Skeleton.vue b/apps/telemetry-dashboard/components/ui/Skeleton.vue deleted file mode 100644 index 051e00e..0000000 --- a/apps/telemetry-dashboard/components/ui/Skeleton.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Tabs.vue b/apps/telemetry-dashboard/components/ui/Tabs.vue deleted file mode 100644 index f0e3ea6..0000000 --- a/apps/telemetry-dashboard/components/ui/Tabs.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/components/ui/Tooltip.vue b/apps/telemetry-dashboard/components/ui/Tooltip.vue deleted file mode 100644 index fc4e267..0000000 --- a/apps/telemetry-dashboard/components/ui/Tooltip.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/composables/use-dashboard.ts b/apps/telemetry-dashboard/composables/use-dashboard.ts deleted file mode 100644 index 4a5c9cc..0000000 --- a/apps/telemetry-dashboard/composables/use-dashboard.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { AdminRange } from '~/shared/types/telemetry' - -export function useDashboardRange() { - return useState('dashboard-range', () => '30d') -} - -export function useDashboardRefresh() { - return useState('dashboard-refresh', () => 0) -} diff --git a/apps/telemetry-dashboard/composables/use-theme.ts b/apps/telemetry-dashboard/composables/use-theme.ts deleted file mode 100644 index 219c650..0000000 --- a/apps/telemetry-dashboard/composables/use-theme.ts +++ /dev/null @@ -1,23 +0,0 @@ -export type ThemeMode = 'light' | 'dark' | 'system' - -export function useTheme() { - const mode = useState('theme-mode', () => 'system') - - function apply(value: ThemeMode): void { - if (!import.meta.client) return - const dark = - value === 'dark' || - (value === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches) - document.documentElement.classList.toggle('dark', dark) - localStorage.setItem('telemetry-admin-theme', value) - } - - onMounted(() => { - const saved = localStorage.getItem('telemetry-admin-theme') as ThemeMode | null - if (saved === 'light' || saved === 'dark' || saved === 'system') mode.value = saved - apply(mode.value) - }) - - watch(mode, apply) - return { mode } -} diff --git a/apps/telemetry-dashboard/eslint.config.mjs b/apps/telemetry-dashboard/eslint.config.mjs deleted file mode 100644 index e9af1eb..0000000 --- a/apps/telemetry-dashboard/eslint.config.mjs +++ /dev/null @@ -1,10 +0,0 @@ -import config from '@modrinth/tooling-config/eslint/nuxt.mjs' - -export default config.append([ - { - rules: { - 'import/no-unresolved': 'off', - 'no-undef': 'off', - }, - }, -]) diff --git a/apps/telemetry-dashboard/layouts/default.vue b/apps/telemetry-dashboard/layouts/default.vue deleted file mode 100644 index d735e40..0000000 --- a/apps/telemetry-dashboard/layouts/default.vue +++ /dev/null @@ -1,229 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/lib/utils.ts b/apps/telemetry-dashboard/lib/utils.ts deleted file mode 100644 index 399b19b..0000000 --- a/apps/telemetry-dashboard/lib/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type ClassValue, clsx } from 'clsx' -import { twMerge } from 'tailwind-merge' - -export function cn(...inputs: ClassValue[]): string { - return twMerge(clsx(inputs)) -} diff --git a/apps/telemetry-dashboard/nuxt.config.ts b/apps/telemetry-dashboard/nuxt.config.ts deleted file mode 100644 index 80490bb..0000000 --- a/apps/telemetry-dashboard/nuxt.config.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { fileURLToPath } from 'node:url' - -const remoteBindingsEnabled = - process.env.NODE_ENV === 'development' && process.env.TELEMETRY_ADMIN_REMOTE_BINDINGS === 'true' - -export default defineNuxtConfig({ - compatibilityDate: '2025-08-13', - devtools: { enabled: false }, - telemetry: false, - css: ['~/assets/styles/tailwind.css'], - app: { - head: { - htmlAttrs: { lang: 'zh-CN' }, - title: 'Axolotl 遥测中心', - meta: [ - { name: 'robots', content: 'noindex, nofollow' }, - { name: 'color-scheme', content: 'light dark' }, - ], - script: [ - { - key: 'theme-init', - innerHTML: - "(function(){try{var t=localStorage.getItem('telemetry-admin-theme')||'system';var d=document.documentElement;var dark=t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches);d.classList.toggle('dark',dark)}catch(e){}})()", - }, - ], - }, - pageTransition: { name: 'dashboard-page', mode: 'out-in' }, - }, - runtimeConfig: { - accessTeamDomain: '', - accessAudience: '', - mockAuth: false, - mockScenario: 'normal', - publicWorkerHealthUrl: 'https://telemetry.axlmc.org/health', - public: { - adminOrigin: 'https://admin.axlmc.org', - }, - }, - postcss: { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, - }, - hooks: { - 'vite:extendConfig'(config, { isClient }) { - if (process.env.NODE_ENV !== 'development') return - if (!config.server) return - const port = isClient ? 24679 : 24680 - config.server.hmr = { port, clientPort: port } - }, - }, - nitro: { - preset: - process.env.NITRO_PRESET || - (remoteBindingsEnabled - ? 'node-server' - : process.env.VERCEL === '1' - ? 'vercel' - : 'cloudflare_module'), - externals: remoteBindingsEnabled ? { external: ['wrangler'] } : undefined, - plugins: remoteBindingsEnabled - ? [fileURLToPath(new URL('./server/dev/remote-bindings.ts', import.meta.url))] - : [], - }, - typescript: { - strict: true, - typeCheck: false, - }, -}) diff --git a/apps/telemetry-dashboard/package.json b/apps/telemetry-dashboard/package.json deleted file mode 100644 index db12adf..0000000 --- a/apps/telemetry-dashboard/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@axolotl/telemetry-dashboard", - "private": true, - "type": "module", - "scripts": { - "build": "nuxi build", - "deploy": "pnpm run build && wrangler deploy", - "dev": "nuxi dev", - "preview": "nuxi preview", - "postinstall": "nuxi prepare", - "format": "prettier --check .", - "lint": "eslint . && prettier --check .", - "fix": "eslint . --fix && prettier --write .", - "typecheck": "nuxi typecheck && tsc --noEmit -p tsconfig.test.json", - "test": "pnpm run test:server && pnpm run test:ui", - "test:server": "vitest run --config vitest.server.config.ts", - "test:ui": "vitest run --config vitest.ui.config.ts", - "prepr": "pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build" - }, - "dependencies": { - "@aws-sdk/client-s3": "^3.1105.0", - "@unovis/vue": "^1.6.1", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "jose": "^6.1.0", - "lucide-vue-next": "^0.468.0", - "nuxt": "=3.20.2", - "reka-ui": "^2.6.0", - "tailwind-merge": "^2.6.0", - "vue": "^3.5.13", - "vue-router": "*", - "zod": "^3.25.76" - }, - "devDependencies": { - "@cloudflare/vitest-pool-workers": "^0.8.69", - "@cloudflare/workers-types": "^5.20260801.1", - "@modrinth/tooling-config": "workspace:*", - "@types/node": "^24", - "@vitejs/plugin-vue": "^5.2.4", - "@vue/test-utils": "^2.4.6", - "autoprefixer": "^10.4.19", - "happy-dom": "^18.0.1", - "postcss": "^8.4.39", - "prettier-plugin-tailwindcss": "^0.6.5", - "tailwindcss": "^3.4.4", - "typescript": "^5.9.2", - "vitest": "^3.2.4", - "wrangler": "^4.28.1" - }, - "prettier": "@modrinth/tooling-config/frontend.prettier.config.cjs" -} diff --git a/apps/telemetry-dashboard/pages/index.vue b/apps/telemetry-dashboard/pages/index.vue deleted file mode 100644 index ceaf6f6..0000000 --- a/apps/telemetry-dashboard/pages/index.vue +++ /dev/null @@ -1,159 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/pages/system.vue b/apps/telemetry-dashboard/pages/system.vue deleted file mode 100644 index e1a1b7e..0000000 --- a/apps/telemetry-dashboard/pages/system.vue +++ /dev/null @@ -1,52 +0,0 @@ - - - diff --git a/apps/telemetry-dashboard/server/api/admin/activity.get.ts b/apps/telemetry-dashboard/server/api/admin/activity.get.ts deleted file mode 100644 index e1d71f1..0000000 --- a/apps/telemetry-dashboard/server/api/admin/activity.get.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineAdminHandler } from '../../utils/handler' -import { getAdminApi } from '../../utils/service' -import { getQueryRecord, parseRange } from '../../utils/validation' - -export default defineAdminHandler(async (event) => - getAdminApi(event).activity(parseRange(getQueryRecord(event).range)), -) diff --git a/apps/telemetry-dashboard/server/api/admin/distributions.get.ts b/apps/telemetry-dashboard/server/api/admin/distributions.get.ts deleted file mode 100644 index 8bb6b9b..0000000 --- a/apps/telemetry-dashboard/server/api/admin/distributions.get.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineAdminHandler } from '../../utils/handler' -import { getAdminApi } from '../../utils/service' -import { getQueryRecord, parseRange } from '../../utils/validation' - -export default defineAdminHandler(async (event) => - getAdminApi(event).distributions(parseRange(getQueryRecord(event).range)), -) diff --git a/apps/telemetry-dashboard/server/api/admin/overview.get.ts b/apps/telemetry-dashboard/server/api/admin/overview.get.ts deleted file mode 100644 index a23740d..0000000 --- a/apps/telemetry-dashboard/server/api/admin/overview.get.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineAdminHandler } from '../../utils/handler' -import { getAdminApi } from '../../utils/service' -import { getQueryRecord, parseRange } from '../../utils/validation' - -export default defineAdminHandler(async (event) => - getAdminApi(event).overview(parseRange(getQueryRecord(event).range)), -) diff --git a/apps/telemetry-dashboard/server/api/admin/session.get.ts b/apps/telemetry-dashboard/server/api/admin/session.get.ts deleted file mode 100644 index f7195cd..0000000 --- a/apps/telemetry-dashboard/server/api/admin/session.get.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineAdminHandler } from '../../utils/handler' -import { getAdminApi, requireSession } from '../../utils/service' - -export default defineAdminHandler(async (event) => { - const session = requireSession(event) - getAdminApi(event) - return { ...session, dataSource: session.mock ? 'fixture' : 'production' } -}) diff --git a/apps/telemetry-dashboard/server/api/admin/system.get.ts b/apps/telemetry-dashboard/server/api/admin/system.get.ts deleted file mode 100644 index f15f865..0000000 --- a/apps/telemetry-dashboard/server/api/admin/system.get.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { defineAdminHandler } from '../../utils/handler' -import { getAdminApi } from '../../utils/service' - -export default defineAdminHandler(async (event) => getAdminApi(event).system()) diff --git a/apps/telemetry-dashboard/server/dev/remote-bindings.ts b/apps/telemetry-dashboard/server/dev/remote-bindings.ts deleted file mode 100644 index 8a76fa1..0000000 --- a/apps/telemetry-dashboard/server/dev/remote-bindings.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createRequire } from 'node:module' - -import type { PlatformProxy } from 'wrangler' - -import type { DashboardBindings } from '../utils/bindings' - -let proxy: PlatformProxy | null = null -const require = createRequire(import.meta.url) - -export default defineNitroPlugin(async (nitroApp) => { - const { getPlatformProxy } = require('wrangler') as typeof import('wrangler') - proxy = await getPlatformProxy({ - configPath: 'wrangler.toml', - persist: false, - remoteBindings: true, - }) - - nitroApp.hooks.hook('request', (event) => { - event.context.cloudflare = { env: proxy?.env ?? {} } - }) - - nitroApp.hooks.hook('close', async () => { - await proxy?.dispose() - proxy = null - }) -}) diff --git a/apps/telemetry-dashboard/server/middleware/admin-auth.ts b/apps/telemetry-dashboard/server/middleware/admin-auth.ts deleted file mode 100644 index bc7161d..0000000 --- a/apps/telemetry-dashboard/server/middleware/admin-auth.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { getHeader } from 'h3' - -import { toAdminHttpError } from '../utils/admin-http-error' -import { - accessSettings, - authenticateAccessToken, - mockAuthEnabled, - mockScenario, - mockSession, -} from '../utils/auth' -import { AdminApiError, unauthorized, unavailable } from '../utils/errors' -import type { AdminEventContext } from '../utils/service' - -export default defineEventHandler(async (event) => { - if (!event.path.startsWith('/api/admin/')) return - try { - const config = useRuntimeConfig(event) - if (mockAuthEnabled(config)) { - ;(event.context as AdminEventContext).adminSession = mockSession(mockScenario(config)) - return - } - const settings = accessSettings(config) - if (!settings) { - if (process.env.NODE_ENV === 'production') throw unavailable() - throw unauthorized() - } - const token = getHeader(event, 'cf-access-jwt-assertion') - ;(event.context as AdminEventContext).adminSession = await authenticateAccessToken( - token, - settings, - ) - } catch (error) { - if (error instanceof AdminApiError) throw toAdminHttpError(error) - throw error - } -}) diff --git a/apps/telemetry-dashboard/server/utils/admin-api.ts b/apps/telemetry-dashboard/server/utils/admin-api.ts deleted file mode 100644 index 02b07b8..0000000 --- a/apps/telemetry-dashboard/server/utils/admin-api.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { - ActivityDto, - AdminRange, - DistributionsDto, - ErrorDetailDto, - ErrorSampleDto, - ErrorsPageDto, - OverviewDto, - SystemDto, -} from '../../shared/types/telemetry' -import type { ErrorQuery } from './validation' - -export interface TelemetryAdminApi { - overview(range: AdminRange): Promise - activity(range: AdminRange): Promise - distributions(range: AdminRange): Promise - errors(query: ErrorQuery): Promise - errorDetail(fingerprint: string): Promise - errorSample(fingerprint: string): Promise - system(): Promise -} diff --git a/apps/telemetry-dashboard/server/utils/admin-http-error.ts b/apps/telemetry-dashboard/server/utils/admin-http-error.ts deleted file mode 100644 index b97b56f..0000000 --- a/apps/telemetry-dashboard/server/utils/admin-http-error.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createError } from 'h3' - -import type { AdminApiError } from './errors' - -export function toAdminHttpError(error: AdminApiError) { - return createError({ - statusCode: error.statusCode, - statusMessage: error.message, - data: { error: { code: error.code, message: error.message } }, - }) -} diff --git a/apps/telemetry-dashboard/server/utils/auth.ts b/apps/telemetry-dashboard/server/utils/auth.ts deleted file mode 100644 index e81df0d..0000000 --- a/apps/telemetry-dashboard/server/utils/auth.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { createRemoteJWKSet, jwtVerify, type JWTVerifyGetKey } from 'jose' - -import type { AdminSessionDto } from '../../shared/types/telemetry' -import { forbidden, unauthorized } from './errors' - -export interface AccessSettings { - teamDomain: string - audience: string -} - -type VerifyKey = JWTVerifyGetKey | CryptoKey | Uint8Array - -export function accessSettings(config: ReturnType): AccessSettings | null { - const teamDomain = String( - process.env.CF_ACCESS_TEAM_DOMAIN || config.accessTeamDomain || '', - ).trim() - const audience = String(process.env.CF_ACCESS_AUDIENCE || config.accessAudience || '').trim() - if (!teamDomain || !audience) return null - return { teamDomain, audience } -} - -export function mockAuthEnabled(config: ReturnType): boolean { - if (process.env.NODE_ENV !== 'development') return false - return String(process.env.TELEMETRY_ADMIN_MOCK_AUTH || config.mockAuth) === 'true' -} - -export function mockScenario(config: ReturnType): string { - return String(process.env.TELEMETRY_ADMIN_MOCK_SCENARIO || config.mockScenario || 'normal') -} - -export async function verifyAccessJwt( - token: string, - settings: AccessSettings, - key?: VerifyKey, -): Promise { - const issuer = `https://${settings.teamDomain}.cloudflareaccess.com` - const verifyKey = key ?? createRemoteJWKSet(new URL(`${issuer}/cdn-cgi/access/certs`)) - try { - const { payload } = await jwtVerify(token, verifyKey, { - issuer, - audience: settings.audience, - algorithms: ['RS256'], - }) - const email = typeof payload.email === 'string' ? payload.email : null - const nameClaim = payload.name ?? payload.common_name ?? email - const name = typeof nameClaim === 'string' && nameClaim.trim() ? nameClaim : 'GitHub member' - return { - identity: { name, email }, - organization: 'Axolotl-Launcher', - logoutUrl: '/cdn-cgi/access/logout', - mock: false, - dataSource: 'production', - } - } catch { - throw unauthorized() - } -} - -export async function authenticateAccessToken( - token: string | null | undefined, - settings: AccessSettings, - key?: VerifyKey, -): Promise { - if (!token) throw unauthorized() - return verifyAccessJwt(token, settings, key) -} - -export function mockSession(scenario: string): AdminSessionDto { - if (scenario === 'forbidden') throw forbidden() - if (scenario === 'unconfigured-auth') throw unauthorized() - return { - identity: { name: '本地开发身份', email: null }, - organization: 'Axolotl-Launcher', - logoutUrl: '/', - mock: true, - dataSource: 'fixture', - } -} diff --git a/apps/telemetry-dashboard/server/utils/bindings.ts b/apps/telemetry-dashboard/server/utils/bindings.ts deleted file mode 100644 index f78e352..0000000 --- a/apps/telemetry-dashboard/server/utils/bindings.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface DashboardBindings { - DB?: D1Database - ERROR_CONTEXTS?: R2Bucket - CLOUDFLARE_ACCOUNT_ID?: string - CLOUDFLARE_ANALYTICS_TOKEN?: string -} - -export function dashboardBindings(event: { context: Record }): DashboardBindings { - const cloudflare = event.context.cloudflare as { env?: DashboardBindings } | undefined - return cloudflare?.env ?? (event.context.env as DashboardBindings | undefined) ?? {} -} diff --git a/apps/telemetry-dashboard/server/utils/d1-admin-api.ts b/apps/telemetry-dashboard/server/utils/d1-admin-api.ts deleted file mode 100644 index 3eafabc..0000000 --- a/apps/telemetry-dashboard/server/utils/d1-admin-api.ts +++ /dev/null @@ -1,838 +0,0 @@ -import type { - ActivityDto, - AdminRange, - DistributionItemDto, - DistributionsDto, - ErrorDetailDto, - ErrorFiltersDto, - ErrorRowDto, - ErrorSampleDto, - ErrorsPageDto, - OverviewDto, - ServiceCheckDto, - SystemDto, -} from '../../shared/types/telemetry' -import type { TelemetryAdminApi } from './admin-api' -import { unavailable } from './errors' -import { type ErrorQuery, rangeDays, startDay } from './validation' - -interface CountRow { - count: number -} - -interface OverviewRow { - total_installations: number - dau: number - wau: number - mau: number - new_today: number - error_occurrences: number - distinct_groups: number - r2_today: number -} - -interface ActivityRow { - day: string - active_installations: number - new_installations: number - error_occurrences: number -} - -interface DistributionRow { - label: string - value: number -} - -interface ErrorRow { - fingerprint: string - error_type: string - latest_message: string - app_version: string - first_seen: string - last_seen: string - occurrence_count: number - affected_installations: number - has_sample: number -} - -interface SampleRegistration { - object_key: string -} - -export interface TelemetryQueryResult> { - results: T[] -} - -export interface TelemetryStatement { - bind(...values: unknown[]): TelemetryStatement - first>(): Promise - all>(): Promise> -} - -export interface TelemetryDatabase { - prepare(sql: string): TelemetryStatement - batch(statements: TelemetryStatement[]): Promise -} - -export interface TelemetryObject { - body: ReadableStream - httpMetadata?: { contentEncoding?: string } -} - -export interface TelemetryObjectStore { - get( - key: string, - options?: { range?: { offset: number; length: number } }, - ): Promise -} - -const SAMPLE_UNCOMPRESSED_LIMIT = 32 * 1024 -const ANALYTICS_ENDPOINT = 'https://api.cloudflare.com/client/v4/graphql' -const WORKERS_FREE_DAILY_REQUESTS = 100_000 -const D1_FREE_DAILY_ROWS_READ = 5_000_000 -const D1_FREE_DAILY_ROWS_WRITTEN = 100_000 -const R2_FREE_MONTHLY_CLASS_A_OPS = 1_000_000 -const USAGE_WARN_RATIO = 0.9 - -const CACHE_TTL_OVERVIEW = 600_000 -const CACHE_TTL_ACTIVITY = 600_000 -const CACHE_TTL_DISTRIBUTIONS = 900_000 -const CACHE_TTL_ERRORS = 1_800_000 -const CACHE_TTL_FILTERS = 900_000 -const CACHE_TTL_DETAIL = 600_000 -const CACHE_TTL_SAMPLE = 600_000 -const CACHE_TTL_SYSTEM = 600_000 - -export interface CloudflareAnalyticsSettings { - accountTag: string - apiToken: string -} - -interface AnalyticsResponse { - data?: Record | null - errors?: Array<{ message?: string }> -} - -interface CacheEntry { - expiresAt: number - value: unknown -} - -const responseCache = new Map() - -function utcDay(now = new Date()): string { - return now.toISOString().slice(0, 10) -} - -function daysAgoUtc(now: Date, days: number): string { - const date = new Date(now) - date.setUTCDate(date.getUTCDate() - days) - return date.toISOString().slice(0, 10) -} - -function formatCount(value: number): string { - return Math.round(value).toLocaleString('en-US') -} - -function errorMessage(error: unknown): string { - const message = error instanceof Error ? error.message : String(error) - return message.slice(0, 160) -} - -async function withTimeout( - milliseconds: number, - run: (signal: AbortSignal) => Promise, -): Promise { - const controller = new AbortController() - const timer = setTimeout(() => controller.abort(), milliseconds) - try { - return await run(controller.signal) - } finally { - clearTimeout(timer) - } -} - -async function queryAnalytics( - fetcher: typeof fetch, - settings: CloudflareAnalyticsSettings, - query: string, -): Promise> { - const response = await withTimeout(10_000, (signal) => - fetcher(ANALYTICS_ENDPOINT, { - method: 'POST', - headers: { - authorization: `Bearer ${settings.apiToken}`, - 'content-type': 'application/json', - }, - body: JSON.stringify({ query }), - signal, - }), - ) - let body: AnalyticsResponse = {} - try { - body = (await response.json()) as AnalyticsResponse - } catch { - // A non-JSON error body is reported through the HTTP status below. - } - if (!response.ok) { - throw new Error(`GraphQL 请求失败(HTTP ${response.status})`) - } - if (body.errors?.length) { - throw new Error( - body.errors - .map((entry) => entry.message ?? '未知错误') - .join(';') - .slice(0, 160), - ) - } - if (!body.data) throw new Error('GraphQL 响应缺少 data') - return body.data -} - -function analyticsRows(data: Record, dataset: string): unknown[] { - const accounts = (data.viewer as { accounts?: unknown } | undefined)?.accounts - if (!Array.isArray(accounts) || accounts.length === 0) return [] - const node = (accounts[0] as Record | undefined)?.[dataset] - return Array.isArray(node) ? node : [] -} - -function sumOf(row: unknown, path: string[]): number { - let current: unknown = row - for (const field of path) { - if (typeof current !== 'object' || current === null) return 0 - current = (current as Record)[field] - } - const parsed = Number(current) - return Number.isFinite(parsed) ? parsed : 0 -} - -function requireRow(rows: unknown[]): Record { - if (rows.length === 0) throw new Error('数据集暂无数据') - return rows[0] as Record -} - -function mapError(row: ErrorRow): ErrorRowDto { - return { - fingerprint: row.fingerprint, - errorType: row.error_type, - latestMessage: row.latest_message, - appVersion: row.app_version, - firstSeen: row.first_seen, - lastSeen: row.last_seen, - occurrenceCount: Number(row.occurrence_count), - affectedInstallations: Number(row.affected_installations), - hasSample: Boolean(row.has_sample), - } -} - -function fillActivity(range: AdminRange, rows: ActivityRow[], now = new Date()): ActivityDto { - const values = new Map(rows.map((row) => [row.day, row])) - const start = new Date(`${startDay(range, now)}T00:00:00.000Z`) - const points = Array.from({ length: rangeDays(range) }, (_, index) => { - const day = new Date(start) - day.setUTCDate(start.getUTCDate() + index) - const key = day.toISOString().slice(0, 10) - const row = values.get(key) - return { - day: key, - activeInstallations: Number(row?.active_installations ?? 0), - newInstallations: Number(row?.new_installations ?? 0), - errorOccurrences: Number(row?.error_occurrences ?? 0), - } - }) - return { range, points } -} - -function service( - status: ServiceCheckDto['status'], - label: string, - detail: string, -): ServiceCheckDto { - return { status, label, detail } -} - -export class D1TelemetryAdminApi implements TelemetryAdminApi { - constructor( - private readonly db: TelemetryDatabase, - private readonly r2: TelemetryObjectStore | undefined, - private readonly options: { - storeErrorContext: boolean - healthUrl: string - analytics?: CloudflareAnalyticsSettings - fetcher?: typeof fetch - now?: () => Date - cacheTtlMs?: number - }, - ) {} - - private now(): Date { - return this.options.now?.() ?? new Date() - } - - private async cached(key: string, ttlMs: number, run: () => Promise): Promise { - const effectiveTtl = this.options.cacheTtlMs ?? ttlMs - if (effectiveTtl <= 0) return run() - const entry = responseCache.get(key) - if (entry && entry.expiresAt > Date.now()) return entry.value as T - const value = await run() - if (responseCache.size > 256) { - for (const [cachedKey, cachedEntry] of responseCache) { - if (cachedEntry.expiresAt <= Date.now()) responseCache.delete(cachedKey) - } - } - responseCache.set(key, { expiresAt: Date.now() + effectiveTtl, value }) - return value - } - - async overview(range: AdminRange): Promise { - return this.cached(`overview:${range}`, CACHE_TTL_OVERVIEW, async () => { - const today = utcDay(this.now()) - const start = startDay(range, this.now()) - const yesterday = daysAgoUtc(this.now(), 1) - const groupCountSql = - range === '365d' - ? '(SELECT COUNT(*) FROM error_groups)' - : '(SELECT COUNT(*) FROM error_range_stats WHERE range_days = ?)' - const groupCountBindings = range === '365d' ? [] : [rangeDays(range)] - const row = await this.db - .prepare( - `SELECT - (SELECT COUNT(*) FROM installations) AS total_installations, - (SELECT COUNT(*) FROM daily_active WHERE day = ?) AS dau, - (SELECT COUNT(DISTINCT installation_hash) FROM daily_active - WHERE day >= date(?, '-6 days') AND day <= ?) AS wau, - (SELECT COUNT(DISTINCT installation_hash) FROM daily_active - WHERE day >= date(?, '-29 days') AND day <= ?) AS mau, - (SELECT COUNT(*) FROM installations WHERE first_seen_day = ?) AS new_today, - (SELECT COALESCE(SUM(error_occurrences), 0) FROM daily_totals - WHERE day >= ? AND day <= ?) - + (SELECT COALESCE(SUM(occurrence_count), 0) FROM error_daily WHERE day = ?) AS error_occurrences, - ${groupCountSql} - + (SELECT COUNT(*) FROM error_daily WHERE day = ?) AS distinct_groups, - (SELECT COALESCE(object_count, 0) FROM error_context_budget WHERE day = ?) AS r2_today`, - ) - .bind(today, today, today, today, today, today, start, yesterday, today, ...groupCountBindings, today, today) - .first() - if (!row) throw unavailable() - const metric = (value: number, label: string) => ({ value: Number(value), label }) - return { - range, - generatedAt: this.now().toISOString(), - metrics: { - totalInstallations: metric(row.total_installations, '历史累计主动同意遥测的安装'), - dau: metric(row.dau, '今日 UTC 唯一活跃安装'), - wau: metric(row.wau, '最近 7 天唯一活跃安装'), - mau: metric(row.mau, '最近 30 天唯一活跃安装'), - newInstallationsToday: metric(row.new_today, '今日 UTC 首次出现'), - errorOccurrences: metric(row.error_occurrences, `${range} 范围内发生次数`), - distinctErrorGroups: metric(row.distinct_groups, `${range} 范围内错误指纹`), - r2SamplesToday: metric(row.r2_today, '今日 UTC 已存储样本'), - }, - } - }) - } - - async activity(range: AdminRange): Promise { - return this.cached(`activity:${range}`, CACHE_TTL_ACTIVITY, async () => { - const today = utcDay(this.now()) - const yesterday = daysAgoUtc(this.now(), 1) - const rows = await this.db - .prepare( - `SELECT day, active_installations, new_installations, error_occurrences - FROM daily_totals WHERE day >= ? AND day <= ? ORDER BY day ASC`, - ) - .bind(startDay(range, this.now()), yesterday) - .all() - const todayRow = await this.db - .prepare( - `SELECT - (SELECT COUNT(*) FROM daily_active WHERE day = ?) AS active_installations, - (SELECT COUNT(*) FROM installations WHERE first_seen_day = ?) AS new_installations, - (SELECT COALESCE(SUM(occurrence_count), 0) FROM error_daily WHERE day = ?) AS error_occurrences`, - ) - .bind(today, today, today) - .first() - const allRows = todayRow ? [...rows.results, todayRow] : rows.results - return fillActivity(range, allRows, this.now()) - }) - } - - async distributions(range: AdminRange): Promise { - return this.cached(`distributions:${range}`, CACHE_TTL_DISTRIBUTIONS, async () => { - const start = startDay(range, this.now()) - const today = utcDay(this.now()) - const query = async ( - field: 'app_version' | 'platform' | 'arch', - ): Promise => { - const result = await this.db - .prepare( - `SELECT ${field} AS label, COUNT(DISTINCT installation_hash) AS value - FROM daily_active WHERE day >= ? AND day <= ? - GROUP BY ${field} ORDER BY value DESC, label ASC LIMIT 12`, - ) - .bind(start, today) - .all() - return result.results.map((row) => ({ label: row.label, value: Number(row.value) })) - } - const [versions, platforms, architectures] = await Promise.all([ - query('app_version'), - query('platform'), - query('arch'), - ]) - return { range, versions, platforms, architectures } - }) - } - - async errors(query: ErrorQuery): Promise { - return this.cached(`errors:${JSON.stringify(query)}`, CACHE_TTL_ERRORS, async () => { - const today = utcDay(this.now()) - const start = startDay(query.range, this.now()) - - const rangeSource = - query.range === '365d' - ? { - sql: `SELECT fingerprint, app_version, first_seen_day AS first_seen, last_seen_day AS last_seen, - occurrence_count, installation_count, latest_error_type, latest_message, - CASE WHEN sample_object_key IS NULL THEN 0 ELSE 1 END AS has_sample - FROM error_groups`, - bindings: [] as unknown[], - } - : { - sql: `SELECT fingerprint, app_version, first_seen, last_seen, - occurrence_count, installation_count, latest_error_type, latest_message, - has_sample - FROM error_range_stats WHERE range_days = ?`, - bindings: [rangeDays(query.range)] as unknown[], - } - - const liveSql = `SELECT ed.fingerprint, ed.app_version, ed.day AS first_seen, ed.day AS last_seen, - SUM(ed.occurrence_count) AS occurrence_count, - SUM(ed.installation_count) AS installation_count, - MAX(ed.latest_error_type) AS latest_error_type, - MAX(ed.latest_message) AS latest_message, - MAX(ed.has_sample) AS has_sample - FROM error_daily ed WHERE ed.day = ? - GROUP BY ed.fingerprint, ed.app_version` - - const scopedSql = `SELECT fingerprint, app_version, first_seen, last_seen, - occurrence_count, installation_count, latest_error_type, latest_message, - has_sample - FROM (${rangeSource.sql}) - UNION ALL - ${liveSql}` - - const bindings: unknown[] = [...rangeSource.bindings, today] - const conditions: string[] = [] - if (query.search) { - const escaped = query.search.toLowerCase().replace(/[\\%_]/g, '\\$&') - conditions.push( - "(LOWER(scoped.fingerprint) LIKE ? ESCAPE '\\' OR LOWER(scoped.latest_message) LIKE ? ESCAPE '\\' OR LOWER(scoped.latest_error_type) LIKE ? ESCAPE '\\')", - ) - bindings.push(`%${escaped}%`, `%${escaped}%`, `%${escaped}%`) - } - if (query.version) { - conditions.push('scoped.app_version = ?') - bindings.push(query.version) - } - if (query.errorType) { - conditions.push('scoped.latest_error_type = ?') - bindings.push(query.errorType) - } - if (query.platform) { - conditions.push( - `EXISTS (SELECT 1 FROM error_reports er - WHERE er.fingerprint = scoped.fingerprint AND er.app_version = scoped.app_version - AND er.platform = ? AND er.day >= ? AND er.day <= ?)`, - ) - bindings.push(query.platform, start, today) - } - if (query.hasSample !== null) { - conditions.push(query.hasSample ? 'scoped.has_sample = 1' : 'scoped.has_sample = 0') - } - const where = conditions.length ? conditions.join(' AND ') : '1 = 1' - - const totalRow = await this.db - .prepare( - `WITH scoped AS (${scopedSql}) - SELECT COUNT(*) AS count FROM ( - SELECT fingerprint FROM scoped WHERE ${where} GROUP BY fingerprint - )`, - ) - .bind(...bindings) - .first() - - const sortColumns: Record = { - lastSeen: 'last_seen', - firstSeen: 'first_seen', - occurrences: 'occurrence_count', - installations: 'affected_installations', - } - const direction = query.direction === 'asc' ? 'ASC' : 'DESC' - const offset = (query.page - 1) * query.pageSize - const rows = await this.db - .prepare( - `WITH scoped AS (${scopedSql}) - SELECT - fingerprint, - MIN(first_seen) AS first_seen, - MAX(last_seen) AS last_seen, - SUM(occurrence_count) AS occurrence_count, - SUM(installation_count) AS affected_installations, - COALESCE((SELECT eg.latest_error_type FROM error_groups eg - WHERE eg.fingerprint = scoped.fingerprint - ORDER BY eg.last_seen_day DESC LIMIT 1), MAX(latest_error_type)) AS error_type, - COALESCE((SELECT eg.latest_message FROM error_groups eg - WHERE eg.fingerprint = scoped.fingerprint - ORDER BY eg.last_seen_day DESC LIMIT 1), MAX(latest_message)) AS latest_message, - COALESCE((SELECT eg.app_version FROM error_groups eg - WHERE eg.fingerprint = scoped.fingerprint - ORDER BY eg.last_seen_day DESC LIMIT 1), MAX(app_version)) AS app_version, - MAX(has_sample) AS has_sample - FROM scoped - WHERE ${where} - GROUP BY fingerprint - ORDER BY ${sortColumns[query.sort]} ${direction}, fingerprint ASC - LIMIT ? OFFSET ?`, - ) - .bind(...bindings, query.pageSize, offset) - .all() - const filters = await this.errorFilters() - const total = Number(totalRow?.count ?? 0) - return { - items: rows.results.map(mapError), - page: query.page, - pageSize: query.pageSize, - total, - totalPages: Math.max(1, Math.ceil(total / query.pageSize)), - filters, - } - }) - } - - private async errorFilters(): Promise { - return this.cached('errorFilters', CACHE_TTL_FILTERS, async () => { - const [versions, platforms, errorTypes] = await Promise.all([ - this.db - .prepare( - 'SELECT DISTINCT app_version AS value FROM error_groups ORDER BY value DESC LIMIT 100', - ) - .all<{ value: string }>(), - this.db - .prepare('SELECT platform AS value FROM platforms ORDER BY value ASC LIMIT 100') - .all<{ value: string }>(), - this.db - .prepare( - 'SELECT DISTINCT latest_error_type AS value FROM error_groups ORDER BY value ASC LIMIT 100', - ) - .all<{ value: string }>(), - ]) - return { - versions: versions.results.map((row) => row.value), - platforms: platforms.results.map((row) => row.value), - errorTypes: errorTypes.results.map((row) => row.value), - } - }) - } - - async errorDetail(fingerprint: string): Promise { - return this.cached(`errorDetail:${fingerprint}`, CACHE_TTL_DETAIL, async () => { - const row = await this.db - .prepare( - `SELECT fingerprint, latest_error_type AS error_type, latest_message, - app_version, first_seen_day AS first_seen, last_seen_day AS last_seen, - occurrence_count, installation_count AS affected_installations, - CASE WHEN sample_object_key IS NULL THEN 0 ELSE 1 END AS has_sample - FROM error_groups WHERE fingerprint = ? ORDER BY last_seen_day DESC LIMIT 1`, - ) - .bind(fingerprint) - .first() - if (row) return { ...mapError(row), route: null, command: null, stack: null } - - const live = await this.db - .prepare( - `SELECT - ed.fingerprint, - MAX(ed.latest_error_type) AS error_type, - MAX(ed.latest_message) AS latest_message, - ed.app_version, - MIN(ed.day) AS first_seen, - MAX(ed.day) AS last_seen, - SUM(ed.occurrence_count) AS occurrence_count, - SUM(ed.installation_count) AS affected_installations, - MAX(ed.has_sample) AS has_sample - FROM error_daily ed - WHERE ed.fingerprint = ? - GROUP BY ed.fingerprint, ed.app_version - ORDER BY last_seen DESC LIMIT 1`, - ) - .bind(fingerprint) - .first() - if (!live) return null - return { ...mapError(live), route: null, command: null, stack: null } - }) - } - - async errorSample(fingerprint: string): Promise { - if (!this.r2) return null - return this.cached(`errorSample:${fingerprint}`, CACHE_TTL_SAMPLE, async () => { - const registration = await this.db - .prepare( - `SELECT object_key FROM error_context_reservations - WHERE fingerprint = ? - ORDER BY created_at DESC LIMIT 1`, - ) - .bind(fingerprint) - .first() - if (!registration) return null - const object = await this.r2!.get(registration.object_key) - if (!object?.body) return null - let stream: ReadableStream = object.body - if ( - object.httpMetadata?.contentEncoding === 'gzip' || - registration.object_key.endsWith('.gz') - ) { - stream = stream.pipeThrough(new DecompressionStream('gzip')) - } - const bytes = await new Response(stream).arrayBuffer() - if (bytes.byteLength > SAMPLE_UNCOMPRESSED_LIMIT) throw unavailable() - let value: Record - try { - value = JSON.parse(new TextDecoder().decode(bytes)) as Record - } catch { - throw unavailable() - } - const app = - typeof value.app === 'object' && value.app ? (value.app as Record) : {} - const text = (input: unknown, limit: number): string => - typeof input === 'string' ? input.slice(0, limit) : '' - const optional = (input: unknown, limit: number): string | null => text(input, limit) || null - return { - fingerprint, - occurredAt: text(value.occurred_at, 64), - appVersion: text(app.version, 64), - platform: text(app.platform, 32), - architecture: text(app.arch, 32), - errorType: text(value.error_type, 128), - message: text(value.message, 1_024), - stack: optional(value.stack, 8_192), - route: optional(value.route, 256), - command: optional(value.command, 256), - context: optional(value.context, 16_384), - } - }) - } - - private async workersRequests24h( - settings: CloudflareAnalyticsSettings, - fetcher: typeof fetch, - now: Date, - ): Promise { - const start = new Date(now.getTime() - 24 * 60 * 60 * 1_000).toISOString() - const data = await queryAnalytics( - fetcher, - settings, - `{ viewer { accounts(filter: { accountTag: "${settings.accountTag}" }) { - workersInvocationsAdaptive( - filter: { datetime_geq: "${start}", datetime_lt: "${now.toISOString()}" } - limit: 1 - ) { sum { requests } } - } } }`, - ) - return sumOf(requireRow(analyticsRows(data, 'workersInvocationsAdaptive')), ['sum', 'requests']) - } - - private async d1UsageToday( - settings: CloudflareAnalyticsSettings, - fetcher: typeof fetch, - now: Date, - ): Promise<{ rowsRead: number; rowsWritten: number }> { - const today = utcDay(now) - const data = await queryAnalytics( - fetcher, - settings, - `{ viewer { accounts(filter: { accountTag: "${settings.accountTag}" }) { - d1AnalyticsAdaptiveGroups( - filter: { date_geq: "${today}", date_leq: "${today}" } - limit: 1 - ) { sum { rowsRead rowsWritten } } - } } }`, - ) - const row = requireRow(analyticsRows(data, 'd1AnalyticsAdaptiveGroups')) - return { - rowsRead: sumOf(row, ['sum', 'rowsRead']), - rowsWritten: sumOf(row, ['sum', 'rowsWritten']), - } - } - - private async r2Operations30d( - settings: CloudflareAnalyticsSettings, - fetcher: typeof fetch, - now: Date, - ): Promise { - const start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1_000).toISOString().slice(0, 10) - const data = await queryAnalytics( - fetcher, - settings, - `{ viewer { accounts(filter: { accountTag: "${settings.accountTag}" }) { - r2OperationsAdaptiveGroups( - filter: { date_geq: "${start}", date_leq: "${utcDay(now)}" } - limit: 1 - ) { sum { requests } } - } } }`, - ) - return sumOf(requireRow(analyticsRows(data, 'r2OperationsAdaptiveGroups')), ['sum', 'requests']) - } - - private async accountUsage(settings: CloudflareAnalyticsSettings): Promise { - if (!/^[0-9a-f]{32}$/i.test(settings.accountTag)) { - return service('unavailable', '未配置', 'CLOUDFLARE_ACCOUNT_ID 格式无效(应为 32 位账户 ID)') - } - const fetcher = this.options.fetcher ?? fetch - const now = this.now() - const parts: string[] = [] - const failures: string[] = [] - let workersRatio = 0 - let d1WriteRatio = 0 - let r2Ratio = 0 - - try { - const requests = await this.workersRequests24h(settings, fetcher, now) - workersRatio = requests / WORKERS_FREE_DAILY_REQUESTS - parts.push( - `Workers ${formatCount(requests)}/${formatCount(WORKERS_FREE_DAILY_REQUESTS)} 请求(24h)`, - ) - } catch (error) { - failures.push(`Workers 用量查询失败:${errorMessage(error)}`) - } - try { - const { rowsRead, rowsWritten } = await this.d1UsageToday(settings, fetcher, now) - d1WriteRatio = rowsWritten / D1_FREE_DAILY_ROWS_WRITTEN - parts.push( - `D1 读 ${formatCount(rowsRead)}/${formatCount(D1_FREE_DAILY_ROWS_READ)}、写 ${formatCount(rowsWritten)}/${formatCount(D1_FREE_DAILY_ROWS_WRITTEN)} 行(今日 UTC)`, - ) - } catch (error) { - failures.push(`D1 用量查询失败:${errorMessage(error)}`) - } - try { - const requests = await this.r2Operations30d(settings, fetcher, now) - r2Ratio = requests / R2_FREE_MONTHLY_CLASS_A_OPS - parts.push( - `R2 ${formatCount(requests)}/${formatCount(R2_FREE_MONTHLY_CLASS_A_OPS)} 操作(30 天,Class A+B 合计)`, - ) - } catch (error) { - failures.push(`R2 用量查询失败:${errorMessage(error)}`) - } - - if (parts.length === 0) { - return service('unavailable', '查询失败', failures.join(';') || 'Analytics API 无可用数据') - } - const detail = failures.length - ? `${parts.join(' · ')};${failures.join(';')}` - : parts.join(' · ') - if (failures.length > 0) return service('degraded', '部分可用', detail) - if (Math.max(workersRatio, d1WriteRatio, r2Ratio) >= USAGE_WARN_RATIO) { - return service('degraded', '接近配额', detail) - } - return service('available', '额度充足', detail) - } - - async system(): Promise { - return this.cached('system', CACHE_TTL_SYSTEM, async () => { - const now = this.now() - let publicWorker = service('unavailable', '不可用', '健康检查端点未响应') - try { - const response = await withTimeout(3_000, (signal) => - (this.options.fetcher ?? fetch)(this.options.healthUrl, { - signal, - headers: { accept: 'application/json' }, - }), - ) - if (response.ok) publicWorker = service('available', '运行正常', '公开采集服务健康检查通过') - } catch { - publicWorker = service('unavailable', '不可用', '健康检查端点未响应') - } - - let d1 = service('unavailable', '不可用', 'D1 查询失败') - let latestDataDay: string | null = null - let budget = 0 - let sampleKey: string | null = null - try { - const result = await this.db.batch([ - this.db.prepare('SELECT MAX(day) AS value FROM daily_totals'), - this.db - .prepare( - 'SELECT COALESCE(object_count, 0) AS value FROM error_context_budget WHERE day = ?', - ) - .bind(utcDay(now)), - this.db.prepare( - 'SELECT object_key AS value FROM error_context_reservations ORDER BY created_at DESC LIMIT 1', - ), - ]) - latestDataDay = - (result[0].results[0] as { value?: string | null } | undefined)?.value ?? null - budget = Number((result[1].results[0] as { value?: number } | undefined)?.value ?? 0) - sampleKey = (result[2].results[0] as { value?: string | null } | undefined)?.value ?? null - d1 = service('available', '可查询', '只读遥测查询可用') - } catch { - d1 = service('unavailable', '不可用', 'D1 查询失败') - } - - let r2 = service('unavailable', '不可用', '没有可读取的登记样本') - if (!this.options.storeErrorContext) { - r2 = service('degraded', '已停用', '错误上下文存储已停用') - } else if (this.r2 && sampleKey) { - try { - const sample = await this.r2.get(sampleKey, { range: { offset: 0, length: 1 } }) - if (sample) { - try { - await sample.body.cancel() - } catch { - // The probe reads a single byte; cancellation failures are irrelevant. - } - r2 = service('available', '可读取', '已确认一个登记样本可读取') - } - } catch { - r2 = service('unavailable', '不可用', '登记样本无法读取') - } - } else if (this.r2) { - r2 = service('degraded', '暂无样本', 'R2 binding 正常,但当前没有登记样本') - } - - const yesterday = daysAgoUtc(now, 1) - const cron = !latestDataDay - ? service('unavailable', '不可用', '没有可用的聚合日期') - : latestDataDay >= yesterday - ? service('available', '数据最新', `最近聚合日期:${latestDataDay}(UTC)`) - : service('degraded', '数据滞后', `最近聚合日期:${latestDataDay}(UTC)`) - - const accountUsage = !this.options.analytics - ? service( - 'unavailable', - '未配置', - '尚未配置 Cloudflare Analytics API:请为 dashboard Worker 设置 CLOUDFLARE_ACCOUNT_ID 与 CLOUDFLARE_ANALYTICS_TOKEN(Account Analytics: Read)', - ) - : await this.accountUsage(this.options.analytics) - - return { - generatedAt: now.toISOString(), - publicWorker, - d1, - r2, - storeErrorContext: this.options.storeErrorContext, - r2Budget: { used: budget, limit: 2000 }, - limits: { - samplesPerGroup: 3, - dailyActiveRetentionDays: 35, - errorReportsRetentionDays: 30, - r2RetentionDays: 30, - errorAggregatesRetentionDays: 365, - }, - latestDataDay, - cron, - accountUsage, - } - }) - } -} - -export { fillActivity } diff --git a/apps/telemetry-dashboard/server/utils/errors.ts b/apps/telemetry-dashboard/server/utils/errors.ts deleted file mode 100644 index a862795..0000000 --- a/apps/telemetry-dashboard/server/utils/errors.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class AdminApiError extends Error { - constructor( - public readonly statusCode: number, - public readonly code: string, - message: string, - ) { - super(message) - this.name = 'AdminApiError' - } -} - -export const unauthorized = () => new AdminApiError(401, 'unauthenticated', '需要登录') -export const forbidden = () => new AdminApiError(403, 'forbidden', '当前身份无权访问') -export const unavailable = () => new AdminApiError(503, 'service_unavailable', '遥测数据暂不可用') diff --git a/apps/telemetry-dashboard/server/utils/handler.ts b/apps/telemetry-dashboard/server/utils/handler.ts deleted file mode 100644 index 9c45384..0000000 --- a/apps/telemetry-dashboard/server/utils/handler.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - createError, - defineEventHandler, - type EventHandler, - type EventHandlerRequest, - isError, -} from 'h3' - -import { toAdminHttpError } from './admin-http-error' -import { AdminApiError } from './errors' - -export function defineAdminHandler( - handler: EventHandler>, -): EventHandler> { - return defineEventHandler(async (event) => { - try { - return await handler(event) - } catch (error) { - if (error instanceof AdminApiError) throw toAdminHttpError(error) - if (isError(error) && 'statusCode' in error && Number(error.statusCode) < 500) throw error - throw createError({ - statusCode: 503, - statusMessage: '遥测数据暂不可用', - data: { - error: { - code: 'service_unavailable', - message: '遥测数据暂不可用', - }, - }, - }) - } - }) -} diff --git a/apps/telemetry-dashboard/server/utils/mock-admin-api.ts b/apps/telemetry-dashboard/server/utils/mock-admin-api.ts deleted file mode 100644 index dcdfd1d..0000000 --- a/apps/telemetry-dashboard/server/utils/mock-admin-api.ts +++ /dev/null @@ -1,232 +0,0 @@ -import type { - ActivityDto, - AdminRange, - DistributionsDto, - ErrorDetailDto, - ErrorSampleDto, - ErrorsPageDto, - OverviewDto, - SystemDto, -} from '../../shared/types/telemetry' -import type { TelemetryAdminApi } from './admin-api' -import { unavailable } from './errors' -import type { ErrorQuery } from './validation' -import { rangeDays } from './validation' - -const FIXTURE_NOW = new Date('2026-08-14T10:00:00.000Z') - -const fixtureErrors: ErrorDetailDto[] = [ - { - fingerprint: 'fixture-render-thread-01', - errorType: 'RenderInitializationError', - latestMessage: 'Fixture renderer could not initialize the selected backend.', - appVersion: '9.4.0-fixture', - firstSeen: '2026-08-03', - lastSeen: '2026-08-14', - occurrenceCount: 184, - affectedInstallations: 41, - hasSample: true, - route: null, - command: null, - stack: null, - }, - { - fingerprint: 'fixture-metadata-timeout-02', - errorType: 'MetadataTimeout', - latestMessage: 'Fixture metadata request exceeded its deadline.', - appVersion: '9.3.2-fixture', - firstSeen: '2026-08-09', - lastSeen: '2026-08-13', - occurrenceCount: 57, - affectedInstallations: 19, - hasSample: false, - route: null, - command: null, - stack: null, - }, - { - fingerprint: 'fixture-runtime-path-03', - errorType: 'RuntimePathError', - latestMessage: 'Fixture Java runtime path was not available.', - appVersion: '9.4.0-fixture', - firstSeen: '2026-08-12', - lastSeen: '2026-08-12', - occurrenceCount: 12, - affectedInstallations: 8, - hasSample: true, - route: null, - command: null, - stack: null, - }, -] - -export class MockTelemetryAdminApi implements TelemetryAdminApi { - constructor(private readonly scenario = 'normal') {} - - private assertAvailable(): void { - if (this.scenario === 'api-error') throw unavailable() - } - - async overview(range: AdminRange): Promise { - this.assertAvailable() - const empty = this.scenario === 'empty' - const value = (normal: number, label: string) => ({ value: empty ? 0 : normal, label }) - return { - range, - generatedAt: FIXTURE_NOW.toISOString(), - metrics: { - totalInstallations: value(18_426, '历史累计主动同意遥测的安装'), - dau: value(2_184, '今日 UTC 唯一活跃安装'), - wau: value(7_932, '最近 7 天唯一活跃安装'), - mau: value(14_806, '最近 30 天唯一活跃安装'), - newInstallationsToday: value(318, '今日 UTC 首次出现'), - errorOccurrences: value(476, `${range} 范围内发生次数`), - distinctErrorGroups: value(39, `${range} 范围内错误指纹`), - r2SamplesToday: value( - this.scenario === 'budget-reached' ? 2_000 : 614, - '今日 UTC 已存储样本', - ), - }, - } - } - - async activity(range: AdminRange): Promise { - this.assertAvailable() - const points = Array.from({ length: rangeDays(range) }, (_, index) => { - const day = new Date(FIXTURE_NOW) - day.setUTCDate(day.getUTCDate() - rangeDays(range) + index + 1) - const wave = Math.round(Math.sin(index / 3) * 90) - return { - day: day.toISOString().slice(0, 10), - activeInstallations: this.scenario === 'empty' ? 0 : 1_820 + index * 9 + wave, - newInstallations: this.scenario === 'empty' ? 0 : 230 + (index % 6) * 17, - errorOccurrences: this.scenario === 'empty' ? 0 : 20 + (index % 5) * 8, - } - }) - return { range, points } - } - - async distributions(range: AdminRange): Promise { - this.assertAvailable() - if (this.scenario === 'empty') return { range, versions: [], platforms: [], architectures: [] } - return { - range, - versions: [ - { label: '9.4.0-fixture', value: 8_214 }, - { label: '9.3.2-fixture', value: 4_981 }, - { label: '9.3.1-fixture', value: 1_760 }, - ], - platforms: [ - { label: 'windows-fixture', value: 10_840 }, - { label: 'linux-fixture', value: 2_934 }, - { label: 'macos-fixture', value: 1_181 }, - ], - architectures: [ - { label: 'x86_64-fixture', value: 12_902 }, - { label: 'aarch64-fixture', value: 2_053 }, - ], - } - } - - async errors(query: ErrorQuery): Promise { - this.assertAvailable() - let rows = this.scenario === 'empty' ? [] : [...fixtureErrors] - if (this.scenario === 'no-sample') rows = rows.map((row) => ({ ...row, hasSample: false })) - const search = query.search.toLowerCase() - rows = rows.filter( - (row) => - (!search || - `${row.fingerprint} ${row.errorType} ${row.latestMessage}` - .toLowerCase() - .includes(search)) && - (!query.version || row.appVersion === query.version) && - (!query.errorType || row.errorType === query.errorType) && - (query.hasSample === null || row.hasSample === query.hasSample), - ) - const keys: Record = { - lastSeen: 'lastSeen', - firstSeen: 'firstSeen', - occurrences: 'occurrenceCount', - installations: 'affectedInstallations', - } - rows.sort((left, right) => { - const a = left[keys[query.sort]] - const b = right[keys[query.sort]] - const compared = - typeof a === 'number' && typeof b === 'number' ? a - b : String(a).localeCompare(String(b)) - return query.direction === 'asc' ? compared : -compared - }) - const total = rows.length - const start = (query.page - 1) * query.pageSize - return { - items: rows.slice(start, start + query.pageSize), - page: query.page, - pageSize: query.pageSize, - total, - totalPages: Math.max(1, Math.ceil(total / query.pageSize)), - filters: { - versions: ['9.4.0-fixture', '9.3.2-fixture', '9.3.1-fixture'], - platforms: ['windows-fixture', 'linux-fixture', 'macos-fixture'], - errorTypes: ['MetadataTimeout', 'RenderInitializationError', 'RuntimePathError'], - }, - } - } - - async errorDetail(fingerprint: string): Promise { - this.assertAvailable() - return fixtureErrors.find((row) => row.fingerprint === fingerprint) ?? null - } - - async errorSample(fingerprint: string): Promise { - this.assertAvailable() - const error = fixtureErrors.find((row) => row.fingerprint === fingerprint) - if (!error?.hasSample || this.scenario === 'no-sample') return null - return { - fingerprint, - occurredAt: '2026-08-14T08:42:11.000Z', - appVersion: error.appVersion, - platform: 'windows-fixture', - architecture: 'x86_64-fixture', - errorType: error.errorType, - message: error.latestMessage, - stack: 'FixtureError: synthetic stack\n at fixture.operation (fixture.ts:14:2)', - route: '/fixture/library', - command: 'fixture-command', - context: '{"fixture":true,"note":"synthetic telemetry context"}', - } - } - - async system(): Promise { - this.assertAvailable() - const budget = this.scenario === 'budget-reached' ? 2_000 : 614 - return { - generatedAt: FIXTURE_NOW.toISOString(), - publicWorker: { - status: 'available', - label: '运行正常', - detail: '模拟健康检查通过', - }, - d1: { status: 'available', label: '可查询', detail: '模拟 D1 可查询' }, - r2: - this.scenario === 'no-sample' - ? { status: 'degraded', label: '暂无样本', detail: '没有登记模拟样本' } - : { status: 'available', label: '可读取', detail: '模拟样本可读取' }, - storeErrorContext: true, - r2Budget: { used: budget, limit: 2_000 }, - limits: { - samplesPerGroup: 3, - dailyActiveRetentionDays: 35, - errorReportsRetentionDays: 30, - r2RetentionDays: 30, - errorAggregatesRetentionDays: 365, - }, - latestDataDay: '2026-08-14', - cron: { status: 'available', label: '数据最新', detail: '最近聚合日期:2026-08-14(UTC)' }, - accountUsage: { - status: 'unavailable', - label: '不可用', - detail: '尚未配置 Analytics API', - }, - } - } -} diff --git a/apps/telemetry-dashboard/server/utils/service.ts b/apps/telemetry-dashboard/server/utils/service.ts deleted file mode 100644 index 4557a93..0000000 --- a/apps/telemetry-dashboard/server/utils/service.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { H3Event } from 'h3' - -import type { AdminSessionDto } from '../../shared/types/telemetry' -import type { TelemetryAdminApi } from './admin-api' -import { mockScenario } from './auth' -import { dashboardBindings } from './bindings' -import { - D1TelemetryAdminApi, - type TelemetryDatabase, -} from './d1-admin-api' -import { unavailable } from './errors' -import { MockTelemetryAdminApi } from './mock-admin-api' -import { remoteTelemetryDataSource } from './vercel-data-source' - -export interface AdminEventContext { - adminSession?: AdminSessionDto - adminApi?: TelemetryAdminApi -} - -export function requireSession(event: H3Event): AdminSessionDto { - const session = (event.context as AdminEventContext).adminSession - if (!session) throw unavailable() - return session -} - -export function getAdminApi(event: H3Event): TelemetryAdminApi { - const context = event.context as AdminEventContext - if (context.adminApi) return context.adminApi - const config = useRuntimeConfig(event) - const bindings = dashboardBindings(event as unknown as { context: Record }) - const remote = remoteTelemetryDataSource() - const db = (bindings.DB as unknown as TelemetryDatabase | undefined) ?? remote?.db - const accountTag = String(bindings.CLOUDFLARE_ACCOUNT_ID ?? '').trim() - const analyticsToken = String(bindings.CLOUDFLARE_ANALYTICS_TOKEN ?? '').trim() - if (db) { - context.adminApi = new D1TelemetryAdminApi(db, undefined, { - storeErrorContext: false, - healthUrl: String(config.publicWorkerHealthUrl), - analytics: - accountTag && analyticsToken ? { accountTag, apiToken: analyticsToken } : undefined, - }) - } else if (context.adminSession?.mock) { - context.adminApi = new MockTelemetryAdminApi(mockScenario(config)) - } else { - throw unavailable() - } - return context.adminApi -} diff --git a/apps/telemetry-dashboard/server/utils/validation.ts b/apps/telemetry-dashboard/server/utils/validation.ts deleted file mode 100644 index c8371f4..0000000 --- a/apps/telemetry-dashboard/server/utils/validation.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { H3Event } from 'h3' - -import { - ADMIN_RANGES, - type AdminRange, - type ErrorSort, - type SortDirection, -} from '../../shared/types/telemetry' -import { AdminApiError } from './errors' - -const ERROR_SORTS = ['lastSeen', 'firstSeen', 'occurrences', 'installations'] as const -const SORT_DIRECTIONS = ['asc', 'desc'] as const - -export interface ErrorQuery { - range: AdminRange - page: number - pageSize: number - search: string - version: string | null - platform: string | null - errorType: string | null - hasSample: boolean | null - sort: ErrorSort - direction: SortDirection -} - -function single(value: unknown): string | undefined { - return Array.isArray(value) ? String(value[0]) : value == null ? undefined : String(value) -} - -function integer(value: unknown, fallback: number, minimum: number, maximum: number): number { - const raw = single(value) - if (raw === undefined || raw === '') return fallback - if (!/^\d+$/.test(raw)) throw new AdminApiError(400, 'invalid_query', 'Invalid query parameters') - const parsed = Number(raw) - if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) { - throw new AdminApiError(400, 'invalid_query', 'Invalid query parameters') - } - return parsed -} - -function limited(value: unknown, maximum: number): string | null { - const parsed = single(value)?.trim() ?? '' - if (!parsed) return null - if (parsed.length > maximum) { - throw new AdminApiError(400, 'invalid_query', 'Invalid query parameters') - } - return parsed -} - -export function parseRange(value: unknown): AdminRange { - const parsed = single(value) ?? '30d' - if (!ADMIN_RANGES.includes(parsed as AdminRange)) { - throw new AdminApiError(400, 'invalid_range', 'Range must be 7d, 30d, 90d, or 365d') - } - return parsed as AdminRange -} - -export function parseErrorQuery(query: Record): ErrorQuery { - const sort = single(query.sort) ?? 'lastSeen' - const direction = single(query.direction) ?? 'desc' - if ( - !ERROR_SORTS.includes(sort as ErrorSort) || - !SORT_DIRECTIONS.includes(direction as SortDirection) - ) { - throw new AdminApiError(400, 'invalid_query', 'Invalid query parameters') - } - const sample = single(query.hasSample) - if (sample !== undefined && sample !== 'true' && sample !== 'false') { - throw new AdminApiError(400, 'invalid_query', 'Invalid query parameters') - } - return { - range: parseRange(query.range), - page: integer(query.page, 1, 1, 100_000), - pageSize: integer(query.pageSize, 25, 1, 100), - search: limited(query.search, 120) ?? '', - version: limited(query.version, 64), - platform: limited(query.platform, 32), - errorType: limited(query.errorType, 128), - hasSample: sample === undefined ? null : sample === 'true', - sort: sort as ErrorSort, - direction: direction as SortDirection, - } -} - -export function getQueryRecord(event: H3Event): Record { - const url = new URL(event.node.req.url ?? '/', 'http://localhost') - return Object.fromEntries(url.searchParams.entries()) -} - -export function rangeDays(range: AdminRange): number { - return Number.parseInt(range, 10) -} - -export function startDay(range: AdminRange, now = new Date()): string { - const date = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())) - date.setUTCDate(date.getUTCDate() - rangeDays(range) + 1) - return date.toISOString().slice(0, 10) -} diff --git a/apps/telemetry-dashboard/server/utils/vercel-data-source.ts b/apps/telemetry-dashboard/server/utils/vercel-data-source.ts deleted file mode 100644 index 0881d95..0000000 --- a/apps/telemetry-dashboard/server/utils/vercel-data-source.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3' - -import type { - TelemetryDatabase, - TelemetryObject, - TelemetryObjectStore, - TelemetryQueryResult, - TelemetryStatement, -} from './d1-admin-api' - -interface D1ApiResponse { - success: boolean - errors?: Array<{ message?: string }> - result?: Array<{ results?: T[]; success?: boolean }> -} - -interface RemoteSettings { - accountId: string - databaseId: string - apiToken: string - r2AccessKeyId: string - r2SecretAccessKey: string - r2BucketName: string -} - -function setting(name: string): string { - return String(process.env[name] ?? '').trim() -} - -function remoteSettings(): RemoteSettings | null { - if (process.env.NODE_ENV !== 'production') return null - const settings = { - accountId: setting('CLOUDFLARE_ACCOUNT_ID'), - databaseId: setting('CLOUDFLARE_D1_DATABASE_ID'), - apiToken: setting('CLOUDFLARE_API_TOKEN'), - r2AccessKeyId: setting('CLOUDFLARE_R2_ACCESS_KEY_ID'), - r2SecretAccessKey: setting('CLOUDFLARE_R2_SECRET_ACCESS_KEY'), - r2BucketName: setting('CLOUDFLARE_R2_BUCKET_NAME'), - } - return Object.values(settings).every(Boolean) ? settings : null -} - -function assertReadOnlySql(sql: string): void { - if (!/^\s*(SELECT|WITH)\b/i.test(sql)) throw new Error('Telemetry database is read-only') -} - -class RemoteD1Statement implements TelemetryStatement { - constructor( - private readonly database: RemoteD1Database, - private readonly sql: string, - private readonly params: unknown[] = [], - ) {} - - bind(...values: unknown[]): TelemetryStatement { - return new RemoteD1Statement(this.database, this.sql, values) - } - - async first>(): Promise { - const result = await this.all() - return result.results[0] ?? null - } - - all>(): Promise> { - return this.database.query(this.sql, this.params) - } -} - -class RemoteD1Database implements TelemetryDatabase { - constructor(private readonly settings: RemoteSettings) {} - - prepare(sql: string): TelemetryStatement { - return new RemoteD1Statement(this, sql) - } - - async batch(statements: TelemetryStatement[]): Promise { - return Promise.all(statements.map((statement) => statement.all())) - } - - async query(sql: string, params: unknown[]): Promise> { - assertReadOnlySql(sql) - const response = await fetch( - `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(this.settings.accountId)}/d1/database/${encodeURIComponent(this.settings.databaseId)}/query`, - { - method: 'POST', - headers: { - authorization: `Bearer ${this.settings.apiToken}`, - 'content-type': 'application/json', - }, - body: JSON.stringify({ sql, params }), - signal: AbortSignal.timeout(10_000), - }, - ) - const body = (await response.json()) as D1ApiResponse - const result = body.result?.[0] - if (!response.ok || !body.success || !result?.success || !result.results) { - throw new Error(body.errors?.[0]?.message || 'Cloudflare D1 query failed') - } - return { results: result.results } - } -} - -class RemoteR2Store implements TelemetryObjectStore { - private readonly client: S3Client - - constructor(private readonly settings: RemoteSettings) { - this.client = new S3Client({ - region: 'auto', - endpoint: `https://${settings.accountId}.r2.cloudflarestorage.com`, - credentials: { - accessKeyId: settings.r2AccessKeyId, - secretAccessKey: settings.r2SecretAccessKey, - }, - }) - } - - async get( - key: string, - options?: { range?: { offset: number; length: number } }, - ): Promise { - const range = options?.range - try { - const object = await this.client.send( - new GetObjectCommand({ - Bucket: this.settings.r2BucketName, - Key: key, - Range: range ? `bytes=${range.offset}-${range.offset + range.length - 1}` : undefined, - }), - ) - if (!object.Body) return null - return { - body: object.Body.transformToWebStream(), - httpMetadata: { contentEncoding: object.ContentEncoding }, - } - } catch (error) { - const status = (error as { $metadata?: { httpStatusCode?: number } }).$metadata - ?.httpStatusCode - if (status === 404) return null - throw error - } - } -} - -let source: { db: TelemetryDatabase; r2: TelemetryObjectStore } | null | undefined - -export function remoteTelemetryDataSource(): { - db: TelemetryDatabase - r2: TelemetryObjectStore -} | null { - if (source !== undefined) return source - const settings = remoteSettings() - source = settings ? { db: new RemoteD1Database(settings), r2: new RemoteR2Store(settings) } : null - return source -} diff --git a/apps/telemetry-dashboard/shared/types/telemetry.ts b/apps/telemetry-dashboard/shared/types/telemetry.ts deleted file mode 100644 index 044536c..0000000 --- a/apps/telemetry-dashboard/shared/types/telemetry.ts +++ /dev/null @@ -1,141 +0,0 @@ -export const ADMIN_RANGES = ['7d', '30d', '90d', '365d'] as const -export type AdminRange = (typeof ADMIN_RANGES)[number] - -export type Availability = 'available' | 'degraded' | 'unavailable' - -export interface AdminSessionDto { - identity: { - name: string - email: string | null - } - organization: 'Axolotl-Launcher' - logoutUrl: string - mock: boolean - dataSource: 'production' | 'fixture' -} - -export interface MetricDto { - value: number - label: string -} - -export interface OverviewDto { - range: AdminRange - generatedAt: string - metrics: { - totalInstallations: MetricDto - dau: MetricDto - wau: MetricDto - mau: MetricDto - newInstallationsToday: MetricDto - errorOccurrences: MetricDto - distinctErrorGroups: MetricDto - r2SamplesToday: MetricDto - } -} - -export interface DailyPointDto { - day: string - activeInstallations: number - newInstallations: number - errorOccurrences: number -} - -export interface ActivityDto { - range: AdminRange - points: DailyPointDto[] -} - -export interface DistributionItemDto { - label: string - value: number -} - -export interface DistributionsDto { - range: AdminRange - versions: DistributionItemDto[] - platforms: DistributionItemDto[] - architectures: DistributionItemDto[] -} - -export type ErrorSort = 'lastSeen' | 'firstSeen' | 'occurrences' | 'installations' -export type SortDirection = 'asc' | 'desc' - -export interface ErrorFiltersDto { - versions: string[] - platforms: string[] - errorTypes: string[] -} - -export interface ErrorRowDto { - fingerprint: string - errorType: string - latestMessage: string - appVersion: string - firstSeen: string - lastSeen: string - occurrenceCount: number - affectedInstallations: number - hasSample: boolean -} - -export interface ErrorsPageDto { - items: ErrorRowDto[] - page: number - pageSize: number - total: number - totalPages: number - filters: ErrorFiltersDto -} - -export interface ErrorDetailDto extends ErrorRowDto { - route: string | null - command: string | null - stack: string | null -} - -export interface ErrorSampleDto { - fingerprint: string - occurredAt: string - appVersion: string - platform: string - architecture: string - errorType: string - message: string - stack: string | null - route: string | null - command: string | null - context: string | null -} - -export interface ServiceCheckDto { - status: Availability - label: string - detail: string -} - -export interface SystemDto { - generatedAt: string - publicWorker: ServiceCheckDto - d1: ServiceCheckDto - r2: ServiceCheckDto - storeErrorContext: boolean - r2Budget: { used: number; limit: 2000 } - limits: { - samplesPerGroup: 3 - dailyActiveRetentionDays: 35 - errorReportsRetentionDays: 30 - r2RetentionDays: 30 - errorAggregatesRetentionDays: 365 - } - latestDataDay: string | null - cron: ServiceCheckDto - accountUsage: ServiceCheckDto -} - -export interface ApiErrorDto { - error: { - code: string - message: string - } -} diff --git a/apps/telemetry-dashboard/tailwind.config.ts b/apps/telemetry-dashboard/tailwind.config.ts deleted file mode 100644 index 5b3a791..0000000 --- a/apps/telemetry-dashboard/tailwind.config.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { Config } from 'tailwindcss' - -export default { - darkMode: ['class'], - content: [ - './app.vue', - './components/**/*.{vue,ts}', - './composables/**/*.ts', - './layouts/**/*.vue', - './pages/**/*.vue', - ], - theme: { - extend: { - colors: { - surface: { - 1: 'hsl(var(--surface-1))', - 2: 'hsl(var(--surface-2))', - 3: 'hsl(var(--surface-3))', - 4: 'hsl(var(--surface-4))', - 5: 'hsl(var(--surface-5))', - }, - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))' }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))', - }, - muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))' }, - accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))' }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))', - }, - card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))' }, - popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))' }, - }, - borderRadius: { - lg: '8px', - md: '6px', - sm: '4px', - }, - fontFamily: { - sans: [ - 'Inter', - 'PingFang SC', - 'Microsoft YaHei', - 'ui-sans-serif', - 'system-ui', - 'sans-serif', - ], - mono: ['JetBrains Mono', 'ui-monospace', 'SFMono-Regular', 'monospace'], - }, - }, - }, - plugins: [], -} satisfies Config diff --git a/apps/telemetry-dashboard/test/server/auth.test.ts b/apps/telemetry-dashboard/test/server/auth.test.ts deleted file mode 100644 index 4399d75..0000000 --- a/apps/telemetry-dashboard/test/server/auth.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { generateKeyPair, SignJWT } from 'jose' -import { afterEach, describe, expect, it } from 'vitest' - -import { authenticateAccessToken, mockAuthEnabled, verifyAccessJwt } from '../../server/utils/auth' - -const settings = { teamDomain: 'fixture-team', audience: 'fixture-audience' } -const issuer = 'https://fixture-team.cloudflareaccess.com' - -async function token( - privateKey: CryptoKey, - overrides: { audience?: string; expiresAt?: number } = {}, -): Promise { - const now = Math.floor(Date.now() / 1_000) - return new SignJWT({ email: 'fixture@example.invalid', name: 'Fixture Operator' }) - .setProtectedHeader({ alg: 'RS256' }) - .setIssuer(issuer) - .setAudience(overrides.audience ?? settings.audience) - .setIssuedAt(now) - .setExpirationTime(overrides.expiresAt ?? now + 600) - .sign(privateKey) -} - -describe('Cloudflare Access authentication', () => { - const previousNodeEnv = process.env.NODE_ENV - - afterEach(() => { - process.env.NODE_ENV = previousNodeEnv - delete process.env.TELEMETRY_ADMIN_MOCK_AUTH - }) - - it('rejects a missing Access assertion', async () => { - await expect(authenticateAccessToken(null, settings)).rejects.toMatchObject({ - statusCode: 401, - code: 'unauthenticated', - }) - }) - - it('rejects the wrong audience and expired tokens, then accepts a valid token', async () => { - const { privateKey, publicKey } = (await generateKeyPair('RS256')) as CryptoKeyPair - await expect( - verifyAccessJwt(await token(privateKey, { audience: 'wrong-audience' }), settings, publicKey), - ).rejects.toMatchObject({ statusCode: 401 }) - await expect( - verifyAccessJwt( - await token(privateKey, { expiresAt: Math.floor(Date.now() / 1_000) - 10 }), - settings, - publicKey, - ), - ).rejects.toMatchObject({ statusCode: 401 }) - - const session = await verifyAccessJwt(await token(privateKey), settings, publicKey) - expect(session).toMatchObject({ - identity: { name: 'Fixture Operator', email: 'fixture@example.invalid' }, - organization: 'Axolotl-Launcher', - mock: false, - dataSource: 'production', - }) - }) - - it('cannot enable MockAuthProvider in production', () => { - process.env.NODE_ENV = 'production' - process.env.TELEMETRY_ADMIN_MOCK_AUTH = 'true' - expect(mockAuthEnabled({ mockAuth: true } as ReturnType)).toBe(false) - }) -}) diff --git a/apps/telemetry-dashboard/test/server/d1-admin-api.test.ts b/apps/telemetry-dashboard/test/server/d1-admin-api.test.ts deleted file mode 100644 index 01e2672..0000000 --- a/apps/telemetry-dashboard/test/server/d1-admin-api.test.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { env } from 'cloudflare:test' -import { beforeEach, describe, expect, it } from 'vitest' - -import { D1TelemetryAdminApi } from '../../server/utils/d1-admin-api' -import { parseErrorQuery } from '../../server/utils/validation' - -const NOW = new Date('2026-08-14T10:00:00.000Z') -const ANALYTICS_URL = 'https://api.cloudflare.com/client/v4/graphql' -const FIXTURE_ACCOUNT_TAG = 'a7659e62e4d157aba4a45e4829b24e91' - -async function gzip(input: string): Promise { - return new Response( - new Blob([input]).stream().pipeThrough(new CompressionStream('gzip')), - ).arrayBuffer() -} - -async function seed(): Promise { - await env.DB.batch([ - env.DB.prepare( - `INSERT INTO installations - (installation_hash, first_seen_at, last_seen_at, first_seen_day, app_version, platform, arch) - VALUES ('fixture-hash-a', 1, 2, '2026-08-13', '9.4.0-fixture', 'windows-fixture', 'x86_64-fixture')`, - ), - env.DB.prepare( - `INSERT INTO installations - (installation_hash, first_seen_at, last_seen_at, first_seen_day, app_version, platform, arch) - VALUES ('fixture-hash-b', 1, 2, '2026-08-14', '9.3.2-fixture', 'linux-fixture', 'aarch64-fixture')`, - ), - env.DB.prepare( - `INSERT INTO daily_active (day, installation_hash, app_version, platform, arch) - VALUES ('2026-08-14', 'fixture-hash-a', '9.4.0-fixture', 'windows-fixture', 'x86_64-fixture')`, - ), - env.DB.prepare( - `INSERT INTO daily_active (day, installation_hash, app_version, platform, arch) - VALUES ('2026-08-14', 'fixture-hash-b', '9.3.2-fixture', 'linux-fixture', 'aarch64-fixture')`, - ), - env.DB.prepare( - `INSERT INTO error_reports - (event_id, installation_hash, day, occurred_at, fingerprint, app_version, platform, arch, - error_type, message, occurrence_count, object_key, created_at) - VALUES ('fixture-event-a', 'fixture-hash-a', '2026-08-14', '2026-08-14T08:00:00Z', - 'fixture-render-01', '9.4.0-fixture', 'windows-fixture', 'x86_64-fixture', - 'RenderFixtureError', 'Fixture render failure', 4, - 'errors/2026-08-14/fixture-render-01/fixture-event-a.json.gz', 1)`, - ), - env.DB.prepare( - `INSERT INTO error_context_reservations - (event_id, day, fingerprint, app_version, object_key, created_at) - VALUES ('fixture-event-a', '2026-08-14', 'fixture-render-01', '9.4.0-fixture', - 'errors/2026-08-14/fixture-render-01/fixture-event-a.json.gz', 1)`, - ), - env.DB.prepare( - `INSERT INTO error_daily - (day, fingerprint, app_version, occurrence_count, installation_count, - latest_error_type, latest_message, has_sample) - VALUES ('2026-08-14', 'fixture-render-01', '9.4.0-fixture', 4, 0, - 'RenderFixtureError', 'Fixture render failure', 1)`, - ), - env.DB.prepare( - `INSERT INTO error_daily_installations - (day, fingerprint, app_version, installation_hash) - VALUES ('2026-08-14', 'fixture-render-01', '9.4.0-fixture', 'fixture-hash-a')`, - ), - env.DB.prepare( - `INSERT INTO daily_totals (day, new_installations, active_installations, error_occurrences, distinct_error_groups) - VALUES ('2026-08-13', 1, 0, 0, 0)`, - ), - env.DB.prepare(`INSERT INTO platforms (platform) VALUES ('windows-fixture')`), - ]) - await env.ERROR_CONTEXTS.put( - 'errors/2026-08-14/fixture-render-01/fixture-event-a.json.gz', - await gzip( - JSON.stringify({ - occurred_at: '2026-08-14T08:00:00Z', - fingerprint: 'fixture-render-01', - app: { - version: '9.4.0-fixture', - platform: 'windows-fixture', - arch: 'x86_64-fixture', - }, - error_type: 'RenderFixtureError', - message: 'Fixture render failure', - stack: 'Fixture stack', - route: '/fixture', - command: 'fixture-command', - context: 'synthetic fixture context', - installation_hash: 'must-not-leak', - object_key: 'must-not-leak', - }), - ), - { httpMetadata: { contentEncoding: 'gzip', contentType: 'application/json' } }, - ) -} - -function api(analytics?: 'configured' | 'partial' | 'unconfigured'): D1TelemetryAdminApi { - const fetcher: typeof fetch = async (input, init) => { - const url = String(input) - if (url === 'https://fixture.invalid/health') { - return new Response(JSON.stringify({ status: 'ok' })) - } - if (url === ANALYTICS_URL) { - const query = JSON.parse(String(init?.body ?? '{}')).query as string - if (analytics === 'partial' && query.includes('workersInvocationsAdaptive')) { - return new Response( - JSON.stringify({ data: null, errors: [{ message: 'fixture analytics failure' }] }), - ) - } - if (query.includes('workersInvocationsAdaptive')) { - return new Response( - JSON.stringify({ - data: { - viewer: { - accounts: [{ workersInvocationsAdaptive: [{ sum: { requests: 12_345 } }] }], - }, - }, - }), - ) - } - if (query.includes('d1AnalyticsAdaptiveGroups')) { - return new Response( - JSON.stringify({ - data: { - viewer: { - accounts: [ - { - d1AnalyticsAdaptiveGroups: [{ sum: { rowsRead: 45_012, rowsWritten: 3_201 } }], - }, - ], - }, - }, - }), - ) - } - if (query.includes('r2OperationsAdaptiveGroups')) { - return new Response( - JSON.stringify({ - data: { - viewer: { - accounts: [{ r2OperationsAdaptiveGroups: [{ sum: { requests: 8_412 } }] }], - }, - }, - }), - ) - } - return new Response( - JSON.stringify({ data: null, errors: [{ message: 'unknown fixture query' }] }), - ) - } - return new Response('not found', { status: 404 }) - } - return new D1TelemetryAdminApi(env.DB, env.ERROR_CONTEXTS, { - storeErrorContext: true, - healthUrl: 'https://fixture.invalid/health', - fetcher, - now: () => NOW, - cacheTtlMs: 0, - analytics: - analytics === 'unconfigured' - ? undefined - : { accountTag: FIXTURE_ACCOUNT_TAG, apiToken: 'fixture-analytics-token' }, - }) -} - -describe('D1TelemetryAdminApi', () => { - beforeEach(seed) - - it('maps D1 aggregates to stable overview and DAU/WAU/MAU DTOs', async () => { - const overview = await api().overview('30d') - expect(overview.metrics.totalInstallations.value).toBe(2) - expect(overview.metrics.dau.value).toBe(2) - expect(overview.metrics.wau.value).toBe(2) - expect(overview.metrics.mau.value).toBe(2) - expect(overview.metrics.errorOccurrences.value).toBe(4) - expect(JSON.stringify(overview)).not.toContain('installation_hash') - }) - - it('supports bound search, filters, sorting, and server pagination', async () => { - const result = await api().errors( - parseErrorQuery({ - range: '30d', - search: 'render', - platform: 'windows-fixture', - page: '1', - pageSize: '25', - sort: 'occurrences', - direction: 'desc', - }), - ) - expect(result.total).toBe(1) - expect(result.items[0]).toMatchObject({ - fingerprint: 'fixture-render-01', - occurrenceCount: 4, - hasSample: true, - }) - expect(JSON.stringify(result)).not.toMatch(/installation_hash|object_key/) - }) - - it('reads only a D1-registered sample and never returns internal keys', async () => { - await env.ERROR_CONTEXTS.put( - 'errors/unregistered.json.gz', - await gzip('{"message":"unregistered"}'), - ) - const registered = await api().errorSample('fixture-render-01') - expect(registered).toMatchObject({ - fingerprint: 'fixture-render-01', - message: 'Fixture render failure', - }) - expect(JSON.stringify(registered)).not.toMatch(/installation_hash|object_key|must-not-leak/) - expect(await api().errorSample('fixture-unregistered')).toBeNull() - }) - - it('reports the unconfigured state when analytics credentials are absent', async () => { - const system = await api('unconfigured').system() - expect(system.accountUsage).toMatchObject({ status: 'unavailable', label: '未配置' }) - expect(system.accountUsage.detail).toContain('尚未配置 Cloudflare Analytics API') - }) - - it('aggregates Workers, D1, and R2 usage into one account usage check', async () => { - const system = await api('configured').system() - expect(system.accountUsage.status).toBe('available') - expect(system.accountUsage.detail).toContain('Workers 12,345/100,000 请求') - expect(system.accountUsage.detail).toContain('写 3,201/100,000 行') - expect(system.accountUsage.detail).toContain('R2 8,412/1,000,000 操作') - }) - - it('degrades when one analytics dataset fails but others respond', async () => { - const system = await api('partial').system() - expect(system.accountUsage).toMatchObject({ status: 'degraded', label: '部分可用' }) - expect(system.accountUsage.detail).toContain('fixture analytics failure') - expect(system.accountUsage.detail).toContain('D1') - expect(system.accountUsage.detail).toContain('R2') - }) -}) diff --git a/apps/telemetry-dashboard/test/server/setup.ts b/apps/telemetry-dashboard/test/server/setup.ts deleted file mode 100644 index 6f4cb84..0000000 --- a/apps/telemetry-dashboard/test/server/setup.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { applyD1Migrations, type D1Migration, env } from 'cloudflare:test' -import { beforeAll, beforeEach } from 'vitest' - -declare module 'cloudflare:test' { - interface ProvidedEnv { - DB: D1Database - ERROR_CONTEXTS: R2Bucket - TEST_MIGRATIONS: D1Migration[] - } -} - -const tables = [ - 'error_context_reservations', - 'error_context_samples', - 'error_context_budget', - 'error_reports', - 'error_daily', - 'error_groups', - 'daily_active', - 'daily_totals', - 'accepted_batches', - 'installations', -] - -beforeAll(async () => { - await applyD1Migrations(env.DB, env.TEST_MIGRATIONS) -}) - -beforeEach(async () => { - await env.DB.batch(tables.map((table) => env.DB.prepare(`DELETE FROM ${table}`))) -}) diff --git a/apps/telemetry-dashboard/test/server/validation.test.ts b/apps/telemetry-dashboard/test/server/validation.test.ts deleted file mode 100644 index c34d86e..0000000 --- a/apps/telemetry-dashboard/test/server/validation.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import { parseErrorQuery, parseRange } from '../../server/utils/validation' - -describe('admin query validation', () => { - it('allows only known UTC ranges', () => { - expect(parseRange('7d')).toBe('7d') - expect(parseRange(undefined)).toBe('30d') - expect(() => parseRange('31d')).toThrowError('Range must be 7d, 30d, 90d, or 365d') - }) - - it('bounds page size, search length, and sort fields', () => { - expect(parseErrorQuery({ page: '2', pageSize: '100', sort: 'occurrences' })).toMatchObject({ - page: 2, - pageSize: 100, - sort: 'occurrences', - }) - expect(() => parseErrorQuery({ pageSize: '101' })).toThrowError('Invalid query parameters') - expect(() => parseErrorQuery({ search: 'x'.repeat(121) })).toThrowError( - 'Invalid query parameters', - ) - expect(() => parseErrorQuery({ sort: 'object_key' })).toThrowError('Invalid query parameters') - }) -}) diff --git a/apps/telemetry-dashboard/test/server/worker.ts b/apps/telemetry-dashboard/test/server/worker.ts deleted file mode 100644 index 850ade6..0000000 --- a/apps/telemetry-dashboard/test/server/worker.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch(): Response { - return new Response('fixture worker') - }, -} diff --git a/apps/telemetry-dashboard/test/ui/states.test.ts b/apps/telemetry-dashboard/test/ui/states.test.ts deleted file mode 100644 index 81b0e71..0000000 --- a/apps/telemetry-dashboard/test/ui/states.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { readFileSync } from 'node:fs' - -import { mount } from '@vue/test-utils' -import { describe, expect, it } from 'vitest' - -import AppState from '../../components/AppState.vue' -import TrendChart from '../../components/charts/TrendChart.vue' -import Skeleton from '../../components/ui/Skeleton.vue' - -describe('dashboard states', () => { - it.each([ - ['error', '遥测数据暂不可用'], - ['unauthenticated', '需要登录'], - ['forbidden', '无权访问'], - ] as const)('renders the %s state', (kind, title) => { - const wrapper = mount(AppState, { props: { kind } }) - expect(wrapper.attributes('data-state')).toBe(kind) - expect(wrapper.text()).toContain(title) - }) - - it('renders stable loading and empty chart states', () => { - expect(mount(Skeleton, { props: { class: 'h-14' } }).classes()).toContain('h-14') - const chart = mount(TrendChart, { - props: { - data: [], - series: [{ key: 'errorOccurrences', label: '错误次数', color: '#d85d4a' }], - }, - }) - expect(chart.get('[data-state="empty"]').text()).toContain('暂无数据') - }) -}) - -describe('responsive theme contract', () => { - it('keeps dark tokens and narrow layouts from creating page overflow', () => { - const root = process.cwd() - const css = readFileSync(`${root}/assets/styles/tailwind.css`, 'utf8') - const layout = readFileSync(`${root}/layouts/default.vue`, 'utf8') - expect(css).toContain('.dark') - expect(css).toContain('overflow-x-hidden') - expect(layout).toContain('min-w-0 md:pl-60') - expect(layout).toContain('w-60 -translate-x-full') - expect(layout).toContain('生产数据') - }) -}) diff --git a/apps/telemetry-dashboard/test/vue-shim.d.ts b/apps/telemetry-dashboard/test/vue-shim.d.ts deleted file mode 100644 index 41bc759..0000000 --- a/apps/telemetry-dashboard/test/vue-shim.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.vue' { - import type { DefineComponent } from 'vue' - - const component: DefineComponent, Record, unknown> - export default component -} diff --git a/apps/telemetry-dashboard/tsconfig.json b/apps/telemetry-dashboard/tsconfig.json deleted file mode 100644 index 84f11d7..0000000 --- a/apps/telemetry-dashboard/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./.nuxt/tsconfig.json", - "compilerOptions": { - "types": ["@cloudflare/workers-types"] - }, - "exclude": ["test", "vitest.server.config.ts", "vitest.ui.config.ts"] -} diff --git a/apps/telemetry-dashboard/tsconfig.test.json b/apps/telemetry-dashboard/tsconfig.test.json deleted file mode 100644 index b931d3b..0000000 --- a/apps/telemetry-dashboard/tsconfig.test.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./.nuxt/tsconfig.json", - "compilerOptions": { - "types": ["@cloudflare/workers-types", "@cloudflare/vitest-pool-workers", "vitest/globals"] - }, - "include": [".nuxt/**/*.d.ts", "server/**/*.ts", "shared/**/*.ts", "test/**/*.ts"] -} diff --git a/apps/telemetry-dashboard/utils/format.ts b/apps/telemetry-dashboard/utils/format.ts deleted file mode 100644 index cba134c..0000000 --- a/apps/telemetry-dashboard/utils/format.ts +++ /dev/null @@ -1,35 +0,0 @@ -export function formatNumber(value: number): string { - return new Intl.NumberFormat('zh-CN').format(value) -} - -export function formatUtcDay(value: string): string { - const parsed = new Date(`${value}T00:00:00.000Z`) - return Number.isNaN(parsed.getTime()) - ? value - : new Intl.DateTimeFormat('zh-CN', { - month: 'numeric', - day: 'numeric', - timeZone: 'UTC', - }).format(parsed) -} - -export function formatUtcTimestamp(value: string): string { - const parsed = new Date(value) - return Number.isNaN(parsed.getTime()) - ? value - : `${new Intl.DateTimeFormat('zh-CN', { - month: '2-digit', - day: 'numeric', - year: 'numeric', - hour: '2-digit', - minute: '2-digit', - hour12: false, - timeZone: 'UTC', - }).format(parsed)}(UTC)` -} - -export function statusCode(error: unknown): number | null { - if (!error || typeof error !== 'object') return null - const value = error as { statusCode?: number; status?: number } - return value.statusCode ?? value.status ?? null -} diff --git a/apps/telemetry-dashboard/vitest.server.config.ts b/apps/telemetry-dashboard/vitest.server.config.ts deleted file mode 100644 index 238d4aa..0000000 --- a/apps/telemetry-dashboard/vitest.server.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineWorkersConfig, readD1Migrations } from '@cloudflare/vitest-pool-workers/config' - -const migrations = await readD1Migrations('../telemetry-worker/migrations') - -export default defineWorkersConfig({ - test: { - include: ['test/server/**/*.test.ts'], - setupFiles: ['./test/server/setup.ts'], - poolOptions: { - workers: { - main: './test/server/worker.ts', - singleWorker: true, - miniflare: { - compatibilityDate: '2025-08-13', - d1Databases: ['DB'], - r2Buckets: ['ERROR_CONTEXTS'], - bindings: { TEST_MIGRATIONS: migrations }, - }, - }, - }, - }, -}) diff --git a/apps/telemetry-dashboard/vitest.ui.config.ts b/apps/telemetry-dashboard/vitest.ui.config.ts deleted file mode 100644 index 2a561cc..0000000 --- a/apps/telemetry-dashboard/vitest.ui.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { fileURLToPath } from 'node:url' - -import vue from '@vitejs/plugin-vue' -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - plugins: [vue()], - resolve: { - alias: { - '~': fileURLToPath(new URL('.', import.meta.url)), - }, - }, - test: { - environment: 'happy-dom', - include: ['test/ui/**/*.test.ts'], - }, -}) diff --git a/apps/telemetry-dashboard/wrangler.toml b/apps/telemetry-dashboard/wrangler.toml deleted file mode 100644 index 2fd45cc..0000000 --- a/apps/telemetry-dashboard/wrangler.toml +++ /dev/null @@ -1,23 +0,0 @@ -name = "axolotl-telemetry-dashboard" -main = ".output/server/index.mjs" -compatibility_date = "2025-08-13" -compatibility_flags = ["nodejs_compat"] -workers_dev = false - -[assets] -directory = ".output/public" -binding = "ASSETS" - -[vars] -NUXT_PUBLIC_ADMIN_ORIGIN = "https://telemetry-api.axlmc.org" -NUXT_PUBLIC_WORKER_HEALTH_URL = "https://telemetry.axlmc.org/health" - -[[d1_databases]] -binding = "DB" -database_name = "axolotl-telemetry" -database_id = "8692e2b1-6156-4b0b-94f5-6e7204c05dff" -remote = true - -[observability] -enabled = true -head_sampling_rate = 0.01 diff --git a/apps/telemetry-worker/README.md b/apps/telemetry-worker/README.md deleted file mode 100644 index 82d69db..0000000 --- a/apps/telemetry-worker/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Starlight telemetry worker - -This Worker accepts only opted-in launcher heartbeat batches. It stores anonymous usage metadata in D1; error reports and error context are not accepted or persisted. - -## Provisioning - -```sh -pnpm exec wrangler d1 create axolotl-telemetry -pnpm exec wrangler secret put INSTALLATION_HMAC_SECRET -pnpm exec wrangler d1 migrations apply axolotl-telemetry --remote -``` - -Replace `database_id` in `wrangler.toml` and keep the Worker on the Free plan. The production custom domain is declared in `wrangler.toml`. Configure Cloudflare usage notifications at 50%, 75%, and 90% for Workers and D1. Do not enable Workers Paid. - -Clients that still have queued error reports receive `400 error_reporting_disabled`; the payload is not logged or stored. Upgrade clients should discard their local error outbox. - -## Storage design - -D1 stays within the Free plan's daily limits (5M rows read / 100k rows written) by avoiding per-event aggregation triggers: - -- `daily_active` inserts feed `wau_seen` / `mau_seen` / `daily_active_dims` through a single lightweight trigger for O(1) WAU/MAU and distribution reads. -- A nightly cron (`runMaintenance`) refreshes usage totals, rolls the active windows, and applies usage-data retention. Legacy error tables remain in the schema for migration compatibility but are no longer written. - -Schema changes are forward-only migrations in `migrations/`; never edit an applied migration. diff --git a/apps/telemetry-worker/migrations/0001_init.sql b/apps/telemetry-worker/migrations/0001_init.sql deleted file mode 100644 index 72e026a..0000000 --- a/apps/telemetry-worker/migrations/0001_init.sql +++ /dev/null @@ -1,219 +0,0 @@ -CREATE TABLE installations ( - installation_hash TEXT PRIMARY KEY, - first_seen_at INTEGER NOT NULL, - last_seen_at INTEGER NOT NULL, - first_seen_day TEXT NOT NULL, - app_version TEXT NOT NULL, - platform TEXT NOT NULL, - arch TEXT NOT NULL -); - -CREATE TABLE daily_active ( - day TEXT NOT NULL, - installation_hash TEXT NOT NULL, - app_version TEXT NOT NULL, - platform TEXT NOT NULL, - arch TEXT NOT NULL, - PRIMARY KEY (day, installation_hash), - FOREIGN KEY (installation_hash) REFERENCES installations (installation_hash) -); - -CREATE TABLE error_reports ( - event_id TEXT PRIMARY KEY, - installation_hash TEXT NOT NULL, - day TEXT NOT NULL, - occurred_at TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - platform TEXT NOT NULL, - arch TEXT NOT NULL, - error_type TEXT NOT NULL, - message TEXT NOT NULL, - occurrence_count INTEGER NOT NULL, - object_key TEXT NULL, - created_at INTEGER NOT NULL, - FOREIGN KEY (installation_hash) REFERENCES installations (installation_hash) -); - -CREATE INDEX error_reports_day ON error_reports (day); -CREATE INDEX error_reports_fingerprint ON error_reports (fingerprint, day); - -CREATE TABLE error_groups ( - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - first_seen_day TEXT NOT NULL, - last_seen_day TEXT NOT NULL, - occurrence_count INTEGER NOT NULL, - installation_count INTEGER NOT NULL, - latest_error_type TEXT NOT NULL, - latest_message TEXT NOT NULL, - sample_object_key TEXT NULL, - PRIMARY KEY (fingerprint, app_version) -); - -CREATE TABLE error_daily ( - day TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - occurrence_count INTEGER NOT NULL, - installation_count INTEGER NOT NULL, - PRIMARY KEY (day, fingerprint, app_version) -); - -CREATE TABLE accepted_batches ( - batch_id TEXT PRIMARY KEY, - installation_hash TEXT NOT NULL, - accepted_at INTEGER NOT NULL -); - -CREATE TABLE daily_totals ( - day TEXT PRIMARY KEY, - new_installations INTEGER NOT NULL DEFAULT 0, - active_installations INTEGER NOT NULL DEFAULT 0, - error_occurrences INTEGER NOT NULL DEFAULT 0, - distinct_error_groups INTEGER NOT NULL DEFAULT 0 -); - -CREATE TABLE error_context_budget ( - day TEXT PRIMARY KEY, - object_count INTEGER NOT NULL CHECK (object_count <= 2000) -); - -CREATE TABLE error_context_samples ( - day TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - sample_count INTEGER NOT NULL CHECK (sample_count <= 3), - PRIMARY KEY (day, fingerprint, app_version) -); - -CREATE TABLE error_context_reservations ( - event_id TEXT PRIMARY KEY, - day TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - object_key TEXT NOT NULL UNIQUE, - created_at INTEGER NOT NULL -); - -CREATE TRIGGER installations_daily_total -AFTER INSERT ON installations -BEGIN - INSERT INTO daily_totals (day, new_installations) - VALUES (NEW.first_seen_day, 1) - ON CONFLICT (day) DO UPDATE - SET new_installations = new_installations + 1; -END; - -CREATE TRIGGER daily_active_total -AFTER INSERT ON daily_active -BEGIN - INSERT INTO daily_totals (day, active_installations) - VALUES (NEW.day, 1) - ON CONFLICT (day) DO UPDATE - SET active_installations = active_installations + 1; -END; - -CREATE TRIGGER error_report_aggregates -AFTER INSERT ON error_reports -BEGIN - INSERT INTO error_groups - ( - fingerprint, - app_version, - first_seen_day, - last_seen_day, - occurrence_count, - installation_count, - latest_error_type, - latest_message, - sample_object_key - ) - VALUES - ( - NEW.fingerprint, - NEW.app_version, - NEW.day, - NEW.day, - NEW.occurrence_count, - 1, - NEW.error_type, - NEW.message, - NEW.object_key - ) - ON CONFLICT (fingerprint, app_version) DO UPDATE - SET - last_seen_day = excluded.last_seen_day, - occurrence_count = occurrence_count + excluded.occurrence_count, - installation_count = installation_count + CASE - WHEN NOT EXISTS ( - SELECT 1 - FROM error_reports AS previous - WHERE - previous.fingerprint = NEW.fingerprint - AND previous.app_version = NEW.app_version - AND previous.installation_hash = NEW.installation_hash - AND previous.event_id != NEW.event_id - ) THEN 1 - ELSE 0 - END, - latest_error_type = excluded.latest_error_type, - latest_message = excluded.latest_message, - sample_object_key = COALESCE(error_groups.sample_object_key, excluded.sample_object_key); - - INSERT INTO error_daily - (day, fingerprint, app_version, occurrence_count, installation_count) - VALUES (NEW.day, NEW.fingerprint, NEW.app_version, NEW.occurrence_count, 1) - ON CONFLICT (day, fingerprint, app_version) DO UPDATE - SET - occurrence_count = occurrence_count + excluded.occurrence_count, - installation_count = installation_count + CASE - WHEN NOT EXISTS ( - SELECT 1 - FROM error_reports AS previous - WHERE - previous.day = NEW.day - AND previous.fingerprint = NEW.fingerprint - AND previous.app_version = NEW.app_version - AND previous.installation_hash = NEW.installation_hash - AND previous.event_id != NEW.event_id - ) THEN 1 - ELSE 0 - END; - - INSERT INTO daily_totals (day, error_occurrences, distinct_error_groups) - VALUES - ( - NEW.day, - NEW.occurrence_count, - CASE - WHEN NOT EXISTS ( - SELECT 1 - FROM error_reports AS previous - WHERE - previous.day = NEW.day - AND previous.fingerprint = NEW.fingerprint - AND previous.app_version = NEW.app_version - AND previous.event_id != NEW.event_id - ) THEN 1 - ELSE 0 - END - ) - ON CONFLICT (day) DO UPDATE - SET - error_occurrences = error_occurrences + excluded.error_occurrences, - distinct_error_groups = distinct_error_groups + excluded.distinct_error_groups; -END; - -CREATE TRIGGER error_context_reservation_budget -AFTER INSERT ON error_context_reservations -BEGIN - INSERT INTO error_context_budget (day, object_count) - VALUES (NEW.day, 1) - ON CONFLICT (day) DO UPDATE SET object_count = object_count + 1; - - INSERT INTO error_context_samples (day, fingerprint, app_version, sample_count) - VALUES (NEW.day, NEW.fingerprint, NEW.app_version, 1) - ON CONFLICT (day, fingerprint, app_version) DO UPDATE - SET sample_count = sample_count + 1; -END; diff --git a/apps/telemetry-worker/migrations/0002_optimize_usage.sql b/apps/telemetry-worker/migrations/0002_optimize_usage.sql deleted file mode 100644 index ef96eb7..0000000 --- a/apps/telemetry-worker/migrations/0002_optimize_usage.sql +++ /dev/null @@ -1,155 +0,0 @@ --- 0002: eliminate per-event aggregation write/read amplification and add missing indexes. --- --- The previous design ran three aggregate UPSERTs (error_groups / error_daily / --- daily_totals) inside an AFTER INSERT trigger for every error report, each with --- a NOT EXISTS subquery that scanned the whole fingerprint history. That single --- INSERT statement accounted for ~8.2M rows read and ~147k rows written per day, --- far beyond the Workers Free daily limits (5M rows read / 100k rows written). --- --- This migration: --- 1. Drops the per-event aggregation triggers; counts now flow through a --- realtime error_daily upsert in the worker and nightly cron rollups. --- 2. Rebuilds error_daily and accepted_batches as WITHOUT ROWID so every --- upsert/insert costs one written row instead of two. --- 3. Adds seen/dimension tables for O(1) distinct-install tracking. --- 4. Swaps the error_reports index so filter queries become point lookups. --- 5. Backfills the new tables from existing data. - -DROP TRIGGER error_report_aggregates; -DROP TRIGGER installations_daily_total; -DROP TRIGGER daily_active_total; - -ALTER TABLE error_daily RENAME TO error_daily_legacy; -CREATE TABLE error_daily ( - day TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - occurrence_count INTEGER NOT NULL, - installation_count INTEGER NOT NULL, - PRIMARY KEY (day, fingerprint, app_version) -) -WITHOUT ROWID; -INSERT INTO error_daily (day, fingerprint, app_version, occurrence_count, installation_count) -SELECT day, fingerprint, app_version, occurrence_count, installation_count -FROM error_daily_legacy; -DROP TABLE error_daily_legacy; - -ALTER TABLE accepted_batches RENAME TO accepted_batches_legacy; -CREATE TABLE accepted_batches ( - batch_id TEXT PRIMARY KEY, - installation_hash TEXT NOT NULL, - accepted_at INTEGER NOT NULL -) -WITHOUT ROWID; -INSERT INTO accepted_batches (batch_id, installation_hash, accepted_at) -SELECT batch_id, installation_hash, accepted_at FROM accepted_batches_legacy; -DROP TABLE accepted_batches_legacy; - -CREATE TABLE error_daily_installations ( - day TEXT NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - installation_hash TEXT NOT NULL, - PRIMARY KEY (day, fingerprint, app_version, installation_hash) -) -WITHOUT ROWID; - -CREATE TABLE error_group_installations ( - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - installation_hash TEXT NOT NULL, - first_seen_day TEXT NOT NULL, - PRIMARY KEY (fingerprint, app_version, installation_hash) -) -WITHOUT ROWID; - -CREATE TABLE wau_seen ( - installation_hash TEXT PRIMARY KEY -) -WITHOUT ROWID; - -CREATE TABLE mau_seen ( - installation_hash TEXT PRIMARY KEY -) -WITHOUT ROWID; - -CREATE TABLE daily_active_dims ( - dimension TEXT NOT NULL, - day TEXT NOT NULL, - label TEXT NOT NULL, - install_count INTEGER NOT NULL, - PRIMARY KEY (dimension, day, label) -) -WITHOUT ROWID; - -CREATE TABLE platforms ( - platform TEXT PRIMARY KEY -) -WITHOUT ROWID; - -CREATE TABLE error_range_stats ( - range_days INTEGER NOT NULL, - fingerprint TEXT NOT NULL, - app_version TEXT NOT NULL, - first_seen TEXT NOT NULL, - last_seen TEXT NOT NULL, - occurrence_count INTEGER NOT NULL, - installation_count INTEGER NOT NULL, - latest_error_type TEXT NOT NULL, - latest_message TEXT NOT NULL, - PRIMARY KEY (range_days, fingerprint, app_version) -) -WITHOUT ROWID; - -DROP INDEX error_reports_fingerprint; -CREATE INDEX error_reports_group_day ON error_reports (fingerprint, app_version, day); -CREATE INDEX installations_first_seen_day ON installations (first_seen_day); -CREATE INDEX error_context_reservations_day ON error_context_reservations (day); -CREATE INDEX error_context_reservations_fingerprint_created ON error_context_reservations ( - fingerprint, - created_at -); -CREATE INDEX error_context_reservations_created_at ON error_context_reservations (created_at); -CREATE INDEX error_groups_last_seen_day ON error_groups (last_seen_day); -CREATE INDEX accepted_batches_accepted_at ON accepted_batches (accepted_at); -CREATE INDEX daily_active_installation ON daily_active (installation_hash, day); - -CREATE TRIGGER daily_active_rollups -AFTER INSERT ON daily_active -BEGIN - INSERT OR IGNORE INTO wau_seen (installation_hash) VALUES (NEW.installation_hash); - INSERT OR IGNORE INTO mau_seen (installation_hash) VALUES (NEW.installation_hash); - INSERT INTO daily_active_dims (dimension, day, label, install_count) - VALUES ('version', NEW.day, NEW.app_version, 1) - ON CONFLICT (dimension, day, label) DO UPDATE SET install_count = install_count + 1; - INSERT INTO daily_active_dims (dimension, day, label, install_count) - VALUES ('platform', NEW.day, NEW.platform, 1) - ON CONFLICT (dimension, day, label) DO UPDATE SET install_count = install_count + 1; - INSERT INTO daily_active_dims (dimension, day, label, install_count) - VALUES ('arch', NEW.day, NEW.arch, 1) - ON CONFLICT (dimension, day, label) DO UPDATE SET install_count = install_count + 1; -END; - -INSERT OR IGNORE INTO wau_seen (installation_hash) -SELECT DISTINCT installation_hash FROM daily_active WHERE day >= date('now', '-6 days'); -INSERT OR IGNORE INTO mau_seen (installation_hash) -SELECT DISTINCT installation_hash FROM daily_active WHERE day >= date('now', '-29 days'); -INSERT OR IGNORE INTO platforms (platform) -SELECT DISTINCT platform FROM error_reports WHERE day >= date('now', '-30 days'); -INSERT OR IGNORE INTO error_group_installations - (fingerprint, app_version, installation_hash, first_seen_day) -SELECT fingerprint, app_version, installation_hash, MIN(day) -FROM error_reports -GROUP BY fingerprint, app_version, installation_hash; -INSERT OR IGNORE INTO daily_active_dims (dimension, day, label, install_count) -SELECT 'version', day, app_version, COUNT(DISTINCT installation_hash) -FROM daily_active -GROUP BY day, app_version; -INSERT OR IGNORE INTO daily_active_dims (dimension, day, label, install_count) -SELECT 'platform', day, platform, COUNT(DISTINCT installation_hash) -FROM daily_active -GROUP BY day, platform; -INSERT OR IGNORE INTO daily_active_dims (dimension, day, label, install_count) -SELECT 'arch', day, arch, COUNT(DISTINCT installation_hash) -FROM daily_active -GROUP BY day, arch; diff --git a/apps/telemetry-worker/migrations/0003_precompute_display_fields.sql b/apps/telemetry-worker/migrations/0003_precompute_display_fields.sql deleted file mode 100644 index 5e4178e..0000000 --- a/apps/telemetry-worker/migrations/0003_precompute_display_fields.sql +++ /dev/null @@ -1,44 +0,0 @@ --- 0003: precompute display fields on error_daily so dashboard list queries stay pure aggregations. --- --- The errors list live branch previously resolved per-group correlated subqueries --- (distinct-install count, latest type/message, sample existence) on every page --- load, costing ~145k rows read per execution. These are now maintained by the --- worker on every upsert and only read back, cutting a list execution to ~15k rows. - -ALTER TABLE error_daily ADD COLUMN latest_error_type TEXT NOT NULL DEFAULT 'Unknown'; -ALTER TABLE error_daily ADD COLUMN latest_message TEXT NOT NULL DEFAULT ''; -ALTER TABLE error_daily ADD COLUMN has_sample INTEGER NOT NULL DEFAULT 0; -ALTER TABLE error_range_stats ADD COLUMN has_sample INTEGER NOT NULL DEFAULT 0; - --- Backfill exact per-day distinct installs for reports ingested before the --- error_daily_installations table existed. -INSERT OR IGNORE INTO error_daily_installations (day, fingerprint, app_version, installation_hash) -SELECT day, fingerprint, app_version, installation_hash -FROM error_reports -WHERE day >= date('now', '-1 days'); - --- Backfill display fields for existing rows from the best available sources. -UPDATE error_daily -SET - latest_error_type = ( - SELECT er.error_type - FROM error_reports AS er - WHERE er.fingerprint = error_daily.fingerprint AND er.app_version = error_daily.app_version - ORDER BY er.occurred_at DESC, er.event_id DESC - LIMIT 1 - ), - latest_message = ( - SELECT er.message - FROM error_reports AS er - WHERE er.fingerprint = error_daily.fingerprint AND er.app_version = error_daily.app_version - ORDER BY er.occurred_at DESC, er.event_id DESC - LIMIT 1 - ), - has_sample = CASE - WHEN EXISTS ( - SELECT 1 - FROM error_context_reservations AS r - WHERE r.fingerprint = error_daily.fingerprint AND r.app_version = error_daily.app_version - ) THEN 1 - ELSE 0 - END; diff --git a/apps/telemetry-worker/migrations/0004_ingestion_limits.sql b/apps/telemetry-worker/migrations/0004_ingestion_limits.sql deleted file mode 100644 index 1c2059b..0000000 --- a/apps/telemetry-worker/migrations/0004_ingestion_limits.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE ingestion_daily ( - day TEXT NOT NULL, - installation_hash TEXT NOT NULL, - accepted_batches INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY (day, installation_hash) -) -WITHOUT ROWID; - -CREATE TABLE ingestion_global_daily ( - day TEXT PRIMARY KEY, - accepted_batches INTEGER NOT NULL DEFAULT 0 -) -WITHOUT ROWID; - -INSERT INTO ingestion_daily (day, installation_hash, accepted_batches) -SELECT date(accepted_at, 'unixepoch'), installation_hash, COUNT(*) -FROM accepted_batches -GROUP BY date(accepted_at, 'unixepoch'), installation_hash; - -INSERT INTO ingestion_global_daily (day, accepted_batches) -SELECT date(accepted_at, 'unixepoch'), COUNT(*) -FROM accepted_batches -GROUP BY date(accepted_at, 'unixepoch'); diff --git a/apps/telemetry-worker/migrations/0005_disable_error_telemetry.sql b/apps/telemetry-worker/migrations/0005_disable_error_telemetry.sql deleted file mode 100644 index 251e5c6..0000000 --- a/apps/telemetry-worker/migrations/0005_disable_error_telemetry.sql +++ /dev/null @@ -1,24 +0,0 @@ --- 0005: stop retaining legacy error telemetry. --- --- Error events are no longer accepted by the worker. Keep the historical --- tables in place so older database snapshots and dashboard migrations remain --- readable, but remove all previously collected error payloads and reset the --- error counters exposed through daily_totals. - -DELETE FROM error_reports; -DELETE FROM error_daily_installations; -DELETE FROM error_group_installations; -DELETE FROM error_daily; -DELETE FROM error_range_stats; -DELETE FROM error_groups; -DELETE FROM error_context_reservations; -DELETE FROM error_context_samples; -DELETE FROM error_context_budget; --- Platforms are repopulated from heartbeat batches and may previously have --- been introduced only by an error report. -DELETE FROM platforms; - -UPDATE daily_totals -SET - error_occurrences = 0, - distinct_error_groups = 0; diff --git a/apps/telemetry-worker/package.json b/apps/telemetry-worker/package.json deleted file mode 100644 index 47faa96..0000000 --- a/apps/telemetry-worker/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@axolotl/telemetry-worker", - "private": true, - "type": "module", - "scripts": { - "configure:rate-limit": "node scripts/configure-rate-limit.mjs", - "dev": "wrangler dev", - "deploy": "wrangler deploy", - "lint": "prettier --check . && tsc --noEmit", - "fix": "prettier --write .", - "test": "vitest run" - }, - "dependencies": { - "hono": "^4.9.2", - "zod": "^3.25.76" - }, - "devDependencies": { - "@cloudflare/vitest-pool-workers": "^0.8.69", - "@cloudflare/workers-types": "^5.20260801.1", - "@types/node": "^24", - "typescript": "^5.9.2", - "vitest": "^3.2.4", - "wrangler": "^4.28.1" - } -} diff --git a/apps/telemetry-worker/scripts/configure-rate-limit.mjs b/apps/telemetry-worker/scripts/configure-rate-limit.mjs deleted file mode 100644 index 937a660..0000000 --- a/apps/telemetry-worker/scripts/configure-rate-limit.mjs +++ /dev/null @@ -1,81 +0,0 @@ -const apiToken = process.env.CF_API_TOKEN -const zoneId = process.env.CF_ZONE_ID - -if (!apiToken || !zoneId) { - throw new Error('CF_API_TOKEN and CF_ZONE_ID are required') -} - -const apiBase = `https://api.cloudflare.com/client/v4/zones/${zoneId}/rulesets` -const ruleDescription = 'Axolotl telemetry batch ingress limit' -const telemetryRule = { - action: 'block', - description: ruleDescription, - enabled: true, - expression: - 'http.host eq "telemetry.axlmc.org" and http.request.method eq "POST" and http.request.uri.path eq "/v1/batch"', - action_parameters: { - ratelimit: { - characteristics: ['ip.src'], - period: 60, - requests_per_period: 2, - mitigation_timeout: 60, - requests_to_origin: false, - }, - }, -} - -async function request(path = '', options = {}) { - const response = await fetch(`${apiBase}${path}`, { - ...options, - headers: { - Authorization: `Bearer ${apiToken}`, - 'Content-Type': 'application/json', - ...(options.headers ?? {}), - }, - }) - const payload = await response.json() - if (!response.ok || !payload.success) { - throw new Error(`Cloudflare API request failed: ${JSON.stringify(payload.errors ?? payload)}`) - } - return payload.result -} - -function editableRule(rule) { - const { action, action_parameters, description, enabled, expression, id, logging } = rule - return { action, action_parameters, description, enabled, expression, id, logging } -} - -const rulesets = await request('?phase=http_ratelimit') -const rateLimitRuleset = rulesets.find((ruleset) => ruleset.phase === 'http_ratelimit') - -if (!rateLimitRuleset) { - await request('', { - method: 'POST', - body: JSON.stringify({ - kind: 'zone', - name: 'Axolotl rate limits', - phase: 'http_ratelimit', - rules: [telemetryRule], - }), - }) - console.log('Created the Axolotl telemetry batch rate-limit rule') -} else { - const existing = await request(`/${rateLimitRuleset.id}`) - const rules = existing.rules.map(editableRule) - const index = rules.findIndex((rule) => rule.description === ruleDescription) - if (index >= 0) { - rules[index] = { ...telemetryRule, id: rules[index].id } - } else { - rules.push(telemetryRule) - } - await request(`/${rateLimitRuleset.id}`, { - method: 'PUT', - body: JSON.stringify({ - name: existing.name, - kind: existing.kind, - phase: existing.phase, - rules, - }), - }) - console.log('Updated the Axolotl telemetry batch rate-limit rule') -} diff --git a/apps/telemetry-worker/src/index.ts b/apps/telemetry-worker/src/index.ts deleted file mode 100644 index 34dfb98..0000000 --- a/apps/telemetry-worker/src/index.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { Hono } from 'hono' - -import { redact, truncateUtf8 } from './redact' -import { batchSchema, type TelemetryBatch } from './schema' - -const MAX_REQUEST_BYTES = 64 * 1024 -const HARD_MAX_BATCHES_PER_INSTALLATION_PER_DAY = 25 -const HARD_MAX_ACCEPTED_BATCHES_PER_DAY = 100_000 - -export interface Bindings { - DB: D1Database - INSTALLATION_HMAC_SECRET: string - INGEST_ENABLED?: string - MAX_BATCHES_PER_INSTALLATION_PER_DAY?: string - MAX_ACCEPTED_BATCHES_PER_DAY?: string -} - -type Variables = { requestId: string } -type IngestionReservation = 'reserved' | 'duplicate' | 'installation_limit' | 'global_limit' - -const app = new Hono<{ Bindings: Bindings; Variables: Variables }>() - -app.use('*', async (context, next) => { - context.set('requestId', crypto.randomUUID()) - await next() - context.header('Cache-Control', 'no-store') -}) - -app.get('/health', (context) => - context.json({ status: 'ok', schema_version: 1 }, 200, { 'Cache-Control': 'no-store' }), -) - -app.post('/v1/batch', async (context) => { - const contentLength = Number(context.req.header('content-length') ?? '0') - if (Number.isFinite(contentLength) && contentLength > MAX_REQUEST_BYTES) { - return context.json({ error: 'request_too_large' }, 413) - } - - const raw = await context.req.arrayBuffer() - if (raw.byteLength > MAX_REQUEST_BYTES) return context.json({ error: 'request_too_large' }, 413) - - let input: unknown - try { - input = JSON.parse(new TextDecoder().decode(raw)) - } catch { - return context.json({ error: 'invalid_json' }, 400) - } - - const parsed = batchSchema.safeParse(input) - if (!parsed.success) { - // Do not accept or log legacy error payloads after error reporting was removed. - if (containsLegacyErrorEvent(input)) - return context.json({ error: 'error_reporting_disabled' }, 400) - return context.json( - { - error: 'invalid_batch', - issues: parsed.error.issues.map((issue) => ({ - path: issue.path.join('.'), - code: issue.code, - })), - }, - 400, - ) - } - if (context.env.INGEST_ENABLED === 'false') { - return context.json({ error: 'ingest_disabled' }, 503, { 'Retry-After': '60' }) - } - if (!context.env.INSTALLATION_HMAC_SECRET || context.env.INSTALLATION_HMAC_SECRET.length < 32) { - return context.json({ error: 'service_unavailable' }, 503) - } - - try { - const accepted = await context.env.DB.prepare( - 'SELECT 1 FROM accepted_batches WHERE batch_id = ? LIMIT 1', - ) - .bind(parsed.data.batch_id) - .first() - if (accepted) return context.json({ accepted: true, duplicate: true }) - - const installationHash = await hmacInstallationId( - context.env.INSTALLATION_HMAC_SECRET, - parsed.data.installation_id, - ) - const limits = ingestionLimits(context.env) - const reservation = await reserveIngestion( - context.env.DB, - parsed.data.batch_id, - installationHash, - limits, - ) - if (reservation === 'duplicate') return context.json({ accepted: true, duplicate: true }) - if (reservation === 'installation_limit') { - return context.json({ error: 'installation_batch_limit' }, 429, { - 'Retry-After': retryAfterSeconds().toString(), - }) - } - if (reservation === 'global_limit') { - console.error('Telemetry ingestion budget exhausted', { limit: limits.global }) - return context.json({ error: 'global_batch_limit' }, 429, { - 'Retry-After': retryAfterSeconds().toString(), - }) - } - - try { - await persistBatch(context.env.DB, sanitizeBatch(parsed.data), installationHash) - } catch (error) { - await rollbackIngestion(context.env.DB, parsed.data.batch_id, installationHash) - throw error - } - return context.json({ accepted: true, duplicate: false }) - } catch (error) { - console.error('Telemetry ingestion failed', { - requestId: context.get('requestId'), - error: error instanceof Error ? error.message : String(error), - }) - return context.json({ error: 'temporarily_unavailable' }, 503) - } -}) - -app.notFound((context) => context.json({ error: 'not_found' }, 404)) -app.onError((error, context) => { - console.error('Unhandled telemetry worker error', { - requestId: context.get('requestId'), - error: error.message, - }) - return context.json({ error: 'temporarily_unavailable' }, 503) -}) - -function containsLegacyErrorEvent(input: unknown): boolean { - if (!input || typeof input !== 'object') return false - const events = (input as { events?: unknown }).events - return ( - Array.isArray(events) && - events.some( - (event) => - Boolean(event) && - typeof event === 'object' && - (event as { type?: unknown }).type === 'error', - ) - ) -} - -async function hmacInstallationId(secret: string, installationId: string): Promise { - const key = await crypto.subtle.importKey( - 'raw', - new TextEncoder().encode(secret), - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign'], - ) - const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(installationId)) - return [...new Uint8Array(signature)].map((byte) => byte.toString(16).padStart(2, '0')).join('') -} - -function ingestionLimits(env: Bindings): { installation: number; global: number } { - return { - installation: Math.min( - positiveInteger( - env.MAX_BATCHES_PER_INSTALLATION_PER_DAY, - HARD_MAX_BATCHES_PER_INSTALLATION_PER_DAY, - ), - HARD_MAX_BATCHES_PER_INSTALLATION_PER_DAY, - ), - global: Math.min( - positiveInteger(env.MAX_ACCEPTED_BATCHES_PER_DAY, HARD_MAX_ACCEPTED_BATCHES_PER_DAY), - HARD_MAX_ACCEPTED_BATCHES_PER_DAY, - ), - } -} - -async function reserveIngestion( - db: D1Database, - batchId: string, - installationHash: string, - limits: { installation: number; global: number }, -): Promise { - const day = utcDay() - const batch = await db - .prepare( - 'INSERT OR IGNORE INTO accepted_batches (batch_id, installation_hash, accepted_at) VALUES (?, ?, unixepoch())', - ) - .bind(batchId, installationHash) - .run() - if (batch.meta.changes !== 1) return 'duplicate' - - const installation = await db - .prepare( - `INSERT INTO ingestion_daily (day, installation_hash, accepted_batches) - VALUES (?, ?, 1) - ON CONFLICT (day, installation_hash) DO UPDATE - SET accepted_batches = accepted_batches + 1 - WHERE accepted_batches < ?`, - ) - .bind(day, installationHash, limits.installation) - .run() - if (installation.meta.changes !== 1) { - await db.prepare('DELETE FROM accepted_batches WHERE batch_id = ?').bind(batchId).run() - return 'installation_limit' - } - - const global = await db - .prepare( - `INSERT INTO ingestion_global_daily (day, accepted_batches) - VALUES (?, 1) - ON CONFLICT (day) DO UPDATE - SET accepted_batches = accepted_batches + 1 - WHERE accepted_batches < ?`, - ) - .bind(day, limits.global) - .run() - if (global.meta.changes !== 1) { - await db.batch([ - db - .prepare( - 'UPDATE ingestion_daily SET accepted_batches = accepted_batches - 1 WHERE day = ? AND installation_hash = ?', - ) - .bind(day, installationHash), - db.prepare('DELETE FROM accepted_batches WHERE batch_id = ?').bind(batchId), - ]) - return 'global_limit' - } - - const currentGlobal = await db - .prepare('SELECT accepted_batches FROM ingestion_global_daily WHERE day = ?') - .bind(day) - .first<{ accepted_batches: number }>() - if (currentGlobal) warnIngestionThresholds(currentGlobal.accepted_batches, limits.global) - return 'reserved' -} - -async function rollbackIngestion( - db: D1Database, - batchId: string, - installationHash: string, -): Promise { - const day = utcDay() - await db.batch([ - db - .prepare('DELETE FROM accepted_batches WHERE batch_id = ? AND installation_hash = ?') - .bind(batchId, installationHash), - db - .prepare( - 'UPDATE ingestion_daily SET accepted_batches = accepted_batches - 1 WHERE day = ? AND installation_hash = ?', - ) - .bind(day, installationHash), - db - .prepare( - 'UPDATE ingestion_global_daily SET accepted_batches = accepted_batches - 1 WHERE day = ?', - ) - .bind(day), - ]) -} - -function sanitizeBatch(batch: TelemetryBatch): TelemetryBatch { - return { - ...batch, - app: { - ...batch.app, - version: truncateUtf8(redact(batch.app.version), 64), - platform: truncateUtf8(redact(batch.app.platform), 32), - arch: truncateUtf8(redact(batch.app.arch), 32), - }, - events: batch.events, - } -} - -async function persistBatch( - db: D1Database, - batch: TelemetryBatch, - installationHash: string, -): Promise { - const acceptedDay = utcDay() - const statements: D1PreparedStatement[] = [ - db - .prepare( - `INSERT OR IGNORE INTO installations ( - installation_hash, first_seen_at, last_seen_at, - first_seen_day, app_version, platform, arch - ) VALUES (?, unixepoch(), unixepoch(), ?, ?, ?, ?)`, - ) - .bind(installationHash, acceptedDay, batch.app.version, batch.app.platform, batch.app.arch), - db.prepare('INSERT OR IGNORE INTO platforms (platform) VALUES (?)').bind(batch.app.platform), - ] - - for (const event of batch.events) { - statements.push( - db - .prepare( - 'INSERT OR IGNORE INTO daily_active (day, installation_hash, app_version, platform, arch) VALUES (?, ?, ?, ?, ?)', - ) - .bind(event.day, installationHash, batch.app.version, batch.app.platform, batch.app.arch), - ) - } - await db.batch(statements) -} - -async function runMaintenance(db: D1Database): Promise { - const now = new Date() - const yesterday = daysAgo(now, 1) - const dayMinus = (days: number) => daysAgo(now, days) - - // Usage-only maintenance. Error aggregate/R2 work was intentionally removed. - await db.batch([ - db - .prepare( - `INSERT INTO daily_totals (day, new_installations, active_installations) - VALUES (?, - (SELECT COUNT(*) FROM installations WHERE first_seen_day = ?), - (SELECT COUNT(*) FROM daily_active WHERE day = ?)) - ON CONFLICT (day) DO UPDATE SET - new_installations = excluded.new_installations, - active_installations = excluded.active_installations`, - ) - .bind(yesterday, yesterday, yesterday), - db - .prepare( - `DELETE FROM wau_seen WHERE NOT EXISTS ( - SELECT 1 FROM daily_active da - WHERE da.installation_hash = wau_seen.installation_hash AND da.day >= ? - )`, - ) - .bind(dayMinus(6)), - db - .prepare( - `DELETE FROM mau_seen WHERE NOT EXISTS ( - SELECT 1 FROM daily_active da - WHERE da.installation_hash = mau_seen.installation_hash AND da.day >= ? - )`, - ) - .bind(dayMinus(29)), - db.prepare("DELETE FROM daily_active WHERE day < date('now', '-35 days')"), - db.prepare("DELETE FROM accepted_batches WHERE accepted_at < unixepoch('now', '-8 days')"), - db.prepare("DELETE FROM ingestion_daily WHERE day < date('now', '-8 days')"), - db.prepare("DELETE FROM ingestion_global_daily WHERE day < date('now', '-8 days')"), - db.prepare("DELETE FROM daily_active_dims WHERE day < date('now', '-365 days')"), - ]) -} - -function daysAgo(now: Date, days: number): string { - const date = new Date(now) - date.setUTCDate(date.getUTCDate() - days) - return date.toISOString().slice(0, 10) -} - -function positiveInteger(value: string | undefined, fallback: number): number { - const parsed = Number(value) - return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback -} - -function utcDay(): string { - return new Date().toISOString().slice(0, 10) -} - -function warnIngestionThresholds(count: number, limit: number): void { - for (const ratio of [0.8, 0.9, 0.95]) { - if (count === Math.ceil(limit * ratio)) { - console.warn('Telemetry ingestion budget threshold reached', { - count, - limit, - percent: ratio * 100, - }) - } - } -} - -function retryAfterSeconds(now = new Date()): number { - const nextDay = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1) - return Math.max(1, Math.ceil((nextDay - now.getTime()) / 1_000)) -} - -export { app, hmacInstallationId, runMaintenance, sanitizeBatch } - -export default { - fetch: app.fetch, - async scheduled(_controller: ScheduledController, env: Bindings, context: ExecutionContext) { - context.waitUntil(runMaintenance(env.DB)) - }, -} satisfies ExportedHandler diff --git a/apps/telemetry-worker/src/redact.ts b/apps/telemetry-worker/src/redact.ts deleted file mode 100644 index aa3f6d3..0000000 --- a/apps/telemetry-worker/src/redact.ts +++ /dev/null @@ -1,35 +0,0 @@ -const encoder = new TextEncoder() -const decoder = new TextDecoder() - -const replacements: Array<[RegExp, string]> = [ - [/\bbearer\s+[a-z0-9._~+/=-]+/gi, 'Bearer '], - [ - /\b(authorization|x-api-key|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|token)\b\s*[:=]\s*[^\s,;]+/gi, - '$1=', - ], - [ - /([?&](?:token|access_token|refresh_token|api_key|key|code|secret|session|signature)=)[^&#\s]+/gi, - '$1', - ], - [/\b[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9.-]+\.[a-z]{2,}\b/gi, ''], - [/\b[a-z]:\\users\\[^\\/\s]+/gi, ''], - [/(?:\/home|\/users)\/[^/\s]+\//gi, '/'], - [/\b[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}\b/gi, ''], -] - -export function redact(input: string): string { - return replacements.reduce( - (value, [pattern, replacement]) => value.replace(pattern, replacement), - input.replaceAll('\0', ''), - ) -} - -export function truncateUtf8(input: string, maxBytes: number): string { - const bytes = encoder.encode(input) - if (bytes.byteLength <= maxBytes) return input - return decoder.decode(bytes.slice(0, maxBytes)).replace(/\uFFFD$/, '') -} - -export function byteLength(input: string): number { - return encoder.encode(input).byteLength -} diff --git a/apps/telemetry-worker/src/schema.ts b/apps/telemetry-worker/src/schema.ts deleted file mode 100644 index 1b802e1..0000000 --- a/apps/telemetry-worker/src/schema.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { z } from 'zod' - -const uuid = z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i) -const timestamp = z.string().datetime({ offset: true }) - -export const heartbeatEventSchema = z - .object({ - type: z.literal('heartbeat'), - event_id: uuid, - occurred_at: timestamp, - day: z.string().regex(/^\d{4}-\d{2}-\d{2}$/), - }) - .strict() - -export const telemetryEventSchema = heartbeatEventSchema - -export const batchSchema = z - .object({ - schema_version: z.literal(1), - batch_id: uuid, - installation_id: uuid, - app: z - .object({ - version: z.string().min(1).max(64), - environment: z.enum(['production', 'development']), - platform: z.string().min(1).max(32), - arch: z.string().min(1).max(32), - }) - .strict(), - events: z.array(telemetryEventSchema).min(1).max(10), - }) - .strict() - -export type TelemetryBatch = z.infer diff --git a/apps/telemetry-worker/test/setup.ts b/apps/telemetry-worker/test/setup.ts deleted file mode 100644 index 07c1eb1..0000000 --- a/apps/telemetry-worker/test/setup.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { applyD1Migrations, env, type D1Migration } from 'cloudflare:test' -import { beforeAll } from 'vitest' - -declare module 'cloudflare:test' { - interface ProvidedEnv { - DB: D1Database - TEST_MIGRATIONS: D1Migration[] - } -} - -beforeAll(async () => { - await applyD1Migrations(env.DB, env.TEST_MIGRATIONS) -}) diff --git a/apps/telemetry-worker/test/worker.test.ts b/apps/telemetry-worker/test/worker.test.ts deleted file mode 100644 index c29202f..0000000 --- a/apps/telemetry-worker/test/worker.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { env, SELF } from 'cloudflare:test' -import { describe, expect, it } from 'vitest' - -import { runMaintenance, type Bindings } from '../src' -import { batchSchema } from '../src/schema' - -declare module 'cloudflare:test' { - interface ProvidedEnv extends Bindings {} -} - -const installationId = '018f6ee8-4cb1-7db3-8a8d-8df96f122d85' - -function batch( - batchId: string, - events: Array>, - clientInstallationId = installationId, -): Record { - return { - schema_version: 1, - batch_id: batchId, - installation_id: clientInstallationId, - app: { - version: '1.7.1', - environment: 'production', - platform: 'windows', - arch: 'x86_64', - }, - events, - } -} - -function heartbeat(eventId: string, day = new Date().toISOString().slice(0, 10)) { - return { type: 'heartbeat', event_id: eventId, occurred_at: `${day}T12:00:00.000Z`, day } -} - -async function post(payload: unknown): Promise { - return await SELF.fetch('https://telemetry.example/v1/batch', { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify(payload), - }) -} - -describe('telemetry worker', () => { - it('serves health without storage access', async () => { - const response = await SELF.fetch('https://telemetry.example/health') - expect(response.status).toBe(200) - expect(await response.json()).toEqual({ status: 'ok', schema_version: 1 }) - }) - - it('accepts strict heartbeat batches and rejects unknown structures', async () => { - const invalid = batch('11111111-1111-4111-8111-111111111111', [ - { ...heartbeat('21111111-1111-4111-8111-111111111111'), unknown: true }, - ]) - expect(batchSchema.safeParse(invalid).success).toBe(false) - expect((await post(invalid)).status).toBe(400) - - const oversized = await SELF.fetch('https://telemetry.example/v1/batch', { - method: 'POST', - body: 'x'.repeat(65 * 1024), - }) - expect(oversized.status).toBe(413) - }) - - it('rejects legacy error batches without charging quota or storing payloads', async () => { - const payload = batch('12111111-1111-4111-8111-111111111111', [ - { - type: 'error', - event_id: '13111111-1111-4111-8111-111111111111', - occurred_at: new Date().toISOString(), - fingerprint: 'a'.repeat(64), - occurrence_count: 1, - error_type: 'legacy_error', - message: 'must not be retained', - }, - ]) - const response = await post(payload) - expect(response.status).toBe(400) - expect(await response.json()).toEqual({ error: 'error_reporting_disabled' }) - - const stored = await env.DB.prepare( - 'SELECT COUNT(*) AS count FROM accepted_batches WHERE batch_id = ?', - ) - .bind('12111111-1111-4111-8111-111111111111') - .first<{ count: number }>() - expect(stored?.count).toBe(0) - }) - - it('enforces the daily installation batch cap without charging duplicates', async () => { - const cappedInstallation = '018f6ee8-4cb1-7db3-8a8d-8df96f122d99' - const day = new Date().toISOString().slice(0, 10) - const payloadFor = (index: number) => - batch( - `60000000-0000-4000-8000-${index.toString().padStart(12, '0')}`, - [heartbeat(`70000000-0000-4000-8000-${index.toString().padStart(12, '0')}`, day)], - cappedInstallation, - ) - - for (let index = 0; index < 25; index++) - expect((await post(payloadFor(index))).status).toBe(200) - expect((await post(payloadFor(0))).status).toBe(200) - - const rejected = await post(payloadFor(25)) - expect(rejected.status).toBe(429) - expect(rejected.headers.get('Retry-After')).not.toBeNull() - }) - - it('opens the global ingestion circuit breaker at 100,000 accepted batches', async () => { - const day = new Date().toISOString().slice(0, 10) - await env.DB.prepare( - `INSERT INTO ingestion_global_daily (day, accepted_batches) - VALUES (?, 99999) - ON CONFLICT (day) DO UPDATE SET accepted_batches = 99999`, - ) - .bind(day) - .run() - - const first = batch( - '80000000-0000-4000-8000-000000000001', - [heartbeat('81000000-0000-4000-8000-000000000001', day)], - '018f6ee8-4cb1-7db3-8a8d-8df96f122d98', - ) - expect((await post(first)).status).toBe(200) - const rejected = await post({ - ...first, - batch_id: '80000000-0000-4000-8000-000000000002', - events: [heartbeat('81000000-0000-4000-8000-000000000002', day)], - }) - expect(rejected.status).toBe(429) - }) - - it('hashes installations and keeps heartbeat batches idempotent', async () => { - const payload = batch('31111111-1111-4111-8111-111111111111', [ - heartbeat('41111111-1111-4111-8111-111111111111', '2026-08-14'), - ]) - expect((await post(payload)).status).toBe(200) - expect((await post(payload)).status).toBe(200) - - const installation = await env.DB.prepare('SELECT installation_hash FROM installations').first<{ - installation_hash: string - }>() - expect(installation?.installation_hash).toMatch(/^[0-9a-f]{64}$/) - expect(installation?.installation_hash).not.toBe(installationId) - const active = await env.DB.prepare('SELECT COUNT(*) AS count FROM daily_active').first<{ - count: number - }>() - expect(active?.count).toBe(1) - }) - - it('keeps offline heartbeat dates for DAU, WAU, and MAU queries', async () => { - const day = (daysAgo: number) => - new Date(Date.now() - daysAgo * 24 * 60 * 60 * 1_000).toISOString().slice(0, 10) - const samples = [ - [ - '32111111-1111-4111-8111-111111111111', - '42111111-1111-4111-8111-111111111111', - installationId.replace(/85$/, '81'), - 0, - ], - [ - '33111111-1111-4111-8111-111111111111', - '43111111-1111-4111-8111-111111111111', - installationId.replace(/85$/, '82'), - 6, - ], - [ - '34111111-1111-4111-8111-111111111111', - '44111111-1111-4111-8111-111111111111', - installationId.replace(/85$/, '83'), - 29, - ], - ] as const - for (const [batchId, eventId, clientId, offset] of samples) { - const heartbeatDay = day(offset) - expect( - (await post(batch(batchId, [heartbeat(eventId, heartbeatDay)], clientId))).status, - ).toBe(200) - } - - const counts = await env.DB.prepare( - `SELECT - COUNT(DISTINCT CASE WHEN day = ? THEN installation_hash END) AS dau, - COUNT(DISTINCT CASE WHEN day >= date(?, '-6 days') THEN installation_hash END) AS wau, - COUNT(DISTINCT CASE WHEN day >= date(?, '-29 days') THEN installation_hash END) AS mau - FROM daily_active`, - ) - .bind(day(0), day(0), day(0)) - .first<{ dau: number; wau: number; mau: number }>() - expect(counts).toEqual({ dau: 1, wau: 2, mau: 3 }) - }) - - it('refreshes usage totals without rebuilding error aggregates', async () => { - const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1_000).toISOString().slice(0, 10) - const response = await post( - batch('a2111111-1111-4111-8111-111111111111', [ - heartbeat('a3111111-1111-4111-8111-111111111111', yesterday), - ]), - ) - expect(response.status).toBe(200) - await runMaintenance(env.DB) - const totals = await env.DB.prepare( - 'SELECT new_installations, active_installations, error_occurrences, distinct_error_groups FROM daily_totals WHERE day = ?', - ) - .bind(yesterday) - .first>() - expect(totals?.active_installations).toBeGreaterThanOrEqual(1) - expect(totals?.error_occurrences).toBe(0) - expect(totals?.distinct_error_groups).toBe(0) - }) -}) diff --git a/apps/telemetry-worker/tsconfig.json b/apps/telemetry-worker/tsconfig.json deleted file mode 100644 index faaa05b..0000000 --- a/apps/telemetry-worker/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "Bundler", - "lib": ["ES2022", "WebWorker"], - "types": ["@cloudflare/workers-types", "@cloudflare/vitest-pool-workers"], - "strict": true, - "noEmit": true, - "skipLibCheck": true - }, - "include": ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"] -} diff --git a/apps/telemetry-worker/vitest.config.ts b/apps/telemetry-worker/vitest.config.ts deleted file mode 100644 index 1b456a4..0000000 --- a/apps/telemetry-worker/vitest.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { defineWorkersConfig, readD1Migrations } from '@cloudflare/vitest-pool-workers/config' - -const migrations = await readD1Migrations('./migrations') - -export default defineWorkersConfig({ - test: { - setupFiles: ['./test/setup.ts'], - poolOptions: { - workers: { - main: './src/index.ts', - singleWorker: true, - miniflare: { - compatibilityDate: '2025-08-13', - d1Databases: ['DB'], - bindings: { - INSTALLATION_HMAC_SECRET: 'test-only-secret-that-is-longer-than-thirty-two-bytes', - INGEST_ENABLED: 'true', - MAX_BATCHES_PER_INSTALLATION_PER_DAY: '25', - MAX_ACCEPTED_BATCHES_PER_DAY: '100000', - TEST_MIGRATIONS: migrations, - }, - }, - }, - }, - }, -}) diff --git a/apps/telemetry-worker/wrangler.toml b/apps/telemetry-worker/wrangler.toml deleted file mode 100644 index 1e4b2f9..0000000 --- a/apps/telemetry-worker/wrangler.toml +++ /dev/null @@ -1,23 +0,0 @@ -name = "axolotl-telemetry" -main = "src/index.ts" -compatibility_date = "2025-08-13" -workers_dev = false -routes = [{ pattern = "telemetry.axlmc.org", custom_domain = true }] - -[vars] -INGEST_ENABLED = "true" -MAX_BATCHES_PER_INSTALLATION_PER_DAY = "25" -MAX_ACCEPTED_BATCHES_PER_DAY = "100000" - -[[d1_databases]] -binding = "DB" -database_name = "axolotl-telemetry" -database_id = "8692e2b1-6156-4b0b-94f5-6e7204c05dff" -migrations_dir = "migrations" - -[triggers] -crons = ["17 0 * * *"] - -[observability] -enabled = true -head_sampling_rate = 0.01 diff --git a/apps/website/package.json b/apps/website/package.json index 1fbbf1f..49a933f 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -27,7 +27,6 @@ "dependencies": { "@modrinth/assets": "workspace:*", "@modrinth/ui": "workspace:*", - "howxm-js": "0.0.10", "intl-messageformat": "^10.7.7", "lru-cache": "^11.2.4", "vue": "^3.5.13", diff --git a/apps/website/src/pages/privacy.vue b/apps/website/src/pages/privacy.vue index c4266d3..3e2af0a 100644 --- a/apps/website/src/pages/privacy.vue +++ b/apps/website/src/pages/privacy.vue @@ -37,7 +37,7 @@ useHead({ eyebrow="隐私政策" title="隐私政策" description="本政策说明 Starlight Launcher 官方网站和桌面应用处理数据的方式,以及第三方服务可能接收的信息。" - updated-at="2026 年 8 月 14 日" + updated-at="2026 年 9 月 13 日" >

1. 适用范围

@@ -54,8 +54,7 @@ useHead({

这些偏好主要保存在 Cookie 或浏览器 localStorage 中,你可通过浏览器设置清除。网站不使用广告 - Cookie。网站接入浩客(Howxm) - 作为第三方用户体验分析和反馈收集服务;其可根据服务配置处理与网站访问、交互、设备或浏览器及网络请求相关的信息,以展示问卷、收集评价和改进网站体验。 + Cookie,也不加载第三方用户行为分析脚本。

网站托管和网络基础设施提供者可能为保障访问、安全和故障排查而处理常规请求信息,例如 IP @@ -71,13 +70,8 @@ useHead({

  • 游戏日志、崩溃信息、缓存、下载记录及更新状态。
  • - 这些数据用于登录、启动游戏、管理内容、诊断故障和提供你主动使用的功能。启动器会在首次运行或功能升级后询问是否允许匿名遥测;未确认或关闭时不会发送遥测。允许后,启动器每天最多发送一次匿名活跃信号,用于统计选择加入遥测的匿名安装量、DAU、WAU、MAU。不会自动上传完整的启动器日志或 Minecraft - 令牌、账户凭据或原始随机安装标识。 -

    -

    - 遥测使用本地生成的随机安装标识;服务端仅保存经密钥 HMAC-SHA256 - 处理后的不可逆标识。你可随时在“隐私与安全”中关闭遥测;关闭后会停止后续采集并清空本地待发送队列,但已经上传的数据仍按下述保留周期清理。Discord - Rich Presence 是独立的本地开关,不属于遥测。 + 这些数据用于登录、启动游戏、管理内容、诊断故障和提供你主动使用的功能。启动器不收集或发送使用遥测、活跃状态、游玩时长、下载来源元数据或 Discord Rich Presence 数据,也不会自动上传完整的启动器日志、Minecraft + 令牌或账户凭据。

    4. 与第三方共享和传输

    @@ -90,8 +84,6 @@ useHead({
  • 你选择的第三方 Yggdrasil 认证服务;
  • Modrinth、CurseForge 及内容作者提供的 API 和下载地址;
  • Update Server、GitHub 及其他用于版本检查、更新或文件分发的服务;
  • -
  • 用于官网用户体验分析和反馈收集的浩客(Howxm);
  • -
  • 用于接收和保存选择加入的匿名遥测数据的 Cloudflare Workers 和 D1;
  • 你主动连接的 Minecraft 服务器或其他外部链接。
  • 项目维护者不会出售你的个人信息。第三方如何保存和使用请求数据,由其各自的隐私政策决定。

    @@ -100,11 +92,6 @@ useHead({

    网站偏好保存在你的浏览器中;启动器数据主要保存在你的设备中。你可以清除浏览器站点数据,或在启动器内移除账户、实例和缓存。卸载应用不一定自动删除全部数据目录,请在确认备份需求后手动清理残留文件。

    -

    - 遥测中的匿名日活记录保留 35 天;每日汇总和匿名安装哈希会长期保留,用于历史趋势和累计安装统计。项目不会在遥测数据库中保存请求 - IP。Cloudflare - 作为基础设施提供者仍可能按其自身政策处理网络请求所必需的信息。 -

    第三方服务保存的数据须通过对应服务的账户设置或隐私渠道管理。项目维护者无法代你访问、导出或删除第三方持有的数据。

    @@ -142,7 +129,7 @@ useHead({ eyebrow="Privacy Policy" title="Privacy Policy" description="This policy explains how the Starlight Launcher official website and desktop application handle data, and what information third-party services may receive." - updated-at="August 14, 2026" + updated-at="September 13, 2026" >

    1. Scope

    @@ -163,12 +150,8 @@ useHead({

    These preferences are mainly stored in cookies or browser localStorage and can be cleared - through your browser settings. The website uses no advertising cookies. It integrates - Howxm as a third-party - user-experience analytics and feedback collection service. Depending on its service - configuration, Howxm may process information related to website visits, interactions, devices - or browsers, and network requests to display surveys, collect ratings, and improve the website - experience. + through your browser settings. The website uses no advertising cookies and loads no + third-party user-behavior analytics scripts.

    Website hosting and network infrastructure providers may process routine request information @@ -192,19 +175,10 @@ useHead({

    This data is used for signing in, launching the game, managing content, diagnosing faults, and - providing features you actively use. The launcher asks whether to allow anonymous telemetry on - first use or after a relevant consent update. No telemetry is sent before confirmation or - while it is disabled. When enabled, the launcher sends at most one anonymous daily activity - signal. This is used to count opted-in anonymous installations, DAU, WAU, and MAU. Full - launcher or Minecraft logs, Minecraft tokens, account credentials, and the original random - installation identifier are not uploaded automatically. -

    -

    - Telemetry uses a random installation identifier generated locally; the service stores only an - irreversible HMAC-SHA256 value produced with a server secret. You can disable telemetry at any time - under Privacy & security. Disabling it stops future collection and clears the local pending - queue, while previously uploaded records are deleted under the retention periods below. - Discord Rich Presence is an independent local setting and is not telemetry. + providing features you actively use. The launcher does not collect or send usage telemetry, + activity status, playtime, download-source metadata, or Discord Rich Presence data. Full + launcher or Minecraft logs, Minecraft tokens, and account credentials are not uploaded + automatically.

    4. Sharing and Transfers with Third Parties

    @@ -223,10 +197,6 @@ useHead({ Update Server, GitHub, and other services used for version checks, updates, or file distribution; -
  • Howxm for official-website user-experience analytics and feedback collection;
  • -
  • - Cloudflare Workers and D1 for opted-in anonymous telemetry ingestion and storage; -
  • Minecraft servers or other external links you connect to.
  • @@ -241,12 +211,6 @@ useHead({ Uninstalling the application does not necessarily delete all data directories automatically; after confirming your backup needs, manually clean up any leftover files.

    -

    - Anonymous daily-active records are retained for 35 days; daily totals and anonymous installation hashes are retained long-term for - historical trends and cumulative installation counts. The project does not store request IP - addresses in the telemetry database. Cloudflare, as the infrastructure provider, may still process information - required to deliver network requests under its own policies. -

    Data stored by third-party services must be managed through the corresponding service's account settings or privacy channels. The project maintainers cannot access, export, or delete diff --git a/apps/website/src/plugins/howxm.client.ts b/apps/website/src/plugins/howxm.client.ts deleted file mode 100644 index 3cc0f59..0000000 --- a/apps/website/src/plugins/howxm.client.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { initHowxm } from 'howxm-js' - -const HOWXM_APP_ID = '0b1c924f-5bca-4865-a52f-e3416fd26e46' - -export default defineNuxtPlugin((nuxtApp) => { - nuxtApp.hook('app:mounted', () => { - initHowxm(HOWXM_APP_ID) - }) -}) diff --git a/packages/app-lib/Cargo.toml b/packages/app-lib/Cargo.toml index 391acfc..2882291 100644 --- a/packages/app-lib/Cargo.toml +++ b/packages/app-lib/Cargo.toml @@ -34,7 +34,6 @@ dashmap = { workspace = true, features = ["serde"] } data-url = { workspace = true } derive_more = { workspace = true, features = ["display"] } dirs = { workspace = true } -discord-rich-presence = { workspace = true } dunce = { workspace = true } either = { workspace = true } encoding_rs = { workspace = true } diff --git a/packages/app-lib/migrations/20260913000000_remove-telemetry.sql b/packages/app-lib/migrations/20260913000000_remove-telemetry.sql new file mode 100644 index 0000000..79a298b --- /dev/null +++ b/packages/app-lib/migrations/20260913000000_remove-telemetry.sql @@ -0,0 +1,9 @@ +UPDATE settings +SET telemetry = FALSE, + telemetry_consent_version = 0, + discord_rpc = FALSE +WHERE id = 0; + +DROP TABLE IF EXISTS telemetry_error_daily; +DROP TABLE IF EXISTS telemetry_outbox; +DROP TABLE IF EXISTS telemetry_identity; diff --git a/packages/app-lib/src/api/instance.rs b/packages/app-lib/src/api/instance.rs index 9f2c61c..a4fc619 100644 --- a/packages/app-lib/src/api/instance.rs +++ b/packages/app-lib/src/api/instance.rs @@ -69,7 +69,6 @@ pub use self::projects::{ pub use self::run::{ GcLaunchIntent, GcLaunchReport, QuickPlayType, kill, run, run_with_extra_launch_args, run_with_extra_launch_args_with_gc, - try_update_playtime_by_instance_id, }; pub use self::upgrade::{ dismiss_instance_post_upgrade_notice, execute_instance_upgrade, diff --git a/packages/app-lib/src/api/instance/projects.rs b/packages/app-lib/src/api/instance/projects.rs index 3104a8b..8d95775 100644 --- a/packages/app-lib/src/api/instance/projects.rs +++ b/packages/app-lib/src/api/instance/projects.rs @@ -6,7 +6,6 @@ use crate::state::instances::{ PackMemberOverrideKind, }; use crate::state::{ContentProvider, ContentSourceKind, ProjectType, State}; -use crate::util::fetch; use modrinth_content_management::{ ContentType, ResolutionPreferences, ResolveContentPlan, }; @@ -85,16 +84,12 @@ pub async fn update_project( pub async fn add_project_from_version( instance_id: &str, version_id: &str, - reason: fetch::DownloadReason, - dependent_on_version_id: Option, ) -> crate::Result { let state = State::get().await?; let project_path = crate::state::instances::commands::add_project_from_version( instance_id, version_id, - reason, - dependent_on_version_id, crate::state::ContentSourceKind::Local, crate::state::instances::ContentOwnershipKind::UserAdded, &state, @@ -674,8 +669,6 @@ pub async fn restore_pack_member_default( crate::state::instances::commands::add_project_from_version( instance_id, release_id, - fetch::DownloadReason::Update, - None, ContentSourceKind::ModrinthModpack, ContentOwnershipKind::PackManaged, &state, diff --git a/packages/app-lib/src/api/instance/run.rs b/packages/app-lib/src/api/instance/run.rs index 52d6f38..d978004 100644 --- a/packages/app-lib/src/api/instance/run.rs +++ b/packages/app-lib/src/api/instance/run.rs @@ -1,17 +1,10 @@ -use super::content::get_projects; use crate::server_address::ServerAddress; use crate::state::{ - Credentials, InstanceInstallStage, InstanceLink, ProcessMetadata, Settings, - State, + Credentials, InstanceInstallStage, ProcessMetadata, Settings, State, }; -use crate::util::fetch; use crate::util::io::IOError; -use crate::util::mojang::mojang_service_url; -use serde_json::json; -use std::collections::HashMap; use std::time::Duration; use tokio::process::Command; -use tracing::{info, warn}; pub use crate::launcher::jvm_args::{GcLaunchIntent, GcLaunchReport}; @@ -253,60 +246,6 @@ async fn run_credentials( mc_set_options.push(("fullscreen".to_string(), "true".to_string())); } - if credentials.is_microsoft() - && let Some(project_id) = server_play_project_id(&context.link) - && !project_id.trim().is_empty() - { - let server_id = uuid::Uuid::new_v4().to_string(); - let join_url = mojang_service_url( - "https://sessionserver.mojang.com/session/minecraft/join", - state.mojang_auth_use_mirror(), - ); - let join_result = fetch::INSECURE_REQWEST_CLIENT - .post(join_url.as_ref()) - .json(&json!({ - "accessToken": &credentials.access_token, - "selectedProfile": credentials.offline_profile.id.simple().to_string(), - "serverId": &server_id, - })) - .timeout(Duration::from_secs(5)) - .send() - .await; - - match join_result { - Ok(resp) if resp.status().is_success() => { - let result = fetch::post_json( - concat!( - env!("MODRINTH_API_BASE_URL"), - "analytics/minecraft-server-play" - ), - json!({ - "project_id": project_id, - "username": &credentials.offline_profile.name, - "server_id": &server_id, - }), - &state.api_semaphore, - &state.pool, - ) - .await; - - match result { - Ok(()) => { - info!( - "Tracked server play for '{project_id}' in analytics" - ) - } - Err(err) => warn!("Failed to report server play: {err:?}"), - } - } - Ok(resp) => warn!( - "Failed to join Mojang session server: HTTP {}", - resp.status() - ), - Err(err) => warn!("Failed to join Mojang session server: {err:?}"), - } - } - if offline_mode { crate::minecraft_skins::flush_pending_skin_change_for_profile( credentials.offline_profile.id, @@ -368,40 +307,6 @@ async fn run_credentials( Ok((process, gc_report)) } -fn server_play_project_id(link: &InstanceLink) -> Option<&String> { - match link { - InstanceLink::ServerProject { project_id } - | InstanceLink::ServerProjectModpack { - server_project_id: project_id, - .. - } => Some(project_id), - InstanceLink::Unmanaged - | InstanceLink::ModrinthModpack { .. } - | InstanceLink::CurseForgeModpack { .. } - | InstanceLink::ImportedModpack { .. } - | InstanceLink::SharedInstance { .. } => None, - } -} - -fn modrinth_pack_version_id(link: &InstanceLink) -> Option<&str> { - match link { - InstanceLink::ModrinthModpack { version_id, .. } - | InstanceLink::ServerProjectModpack { - content_version_id: version_id, - .. - } => Some(version_id), - InstanceLink::Unmanaged - | InstanceLink::ServerProject { .. } - | InstanceLink::CurseForgeModpack { .. } - | InstanceLink::ImportedModpack { .. } - | InstanceLink::SharedInstance { .. } => None, - } -} - -fn playtime_api_url(base_url: &str) -> String { - format!("{}/analytics/playtime", base_url.trim_end_matches('/')) -} - pub async fn kill(instance_id: &str) -> crate::Result<()> { let state = State::get().await?; let processes = @@ -413,104 +318,3 @@ pub async fn kill(instance_id: &str) -> crate::Result<()> { Ok(()) } - -#[tracing::instrument] -pub async fn try_update_playtime_by_instance_id( - instance_id: &str, -) -> crate::Result<()> { - let state = State::get().await?; - let context = - crate::state::instances::commands::get_instance_launch_context( - instance_id, - &state.pool, - ) - .await? - .ok_or_else(|| { - crate::ErrorKind::OtherError(format!( - "Tried to update playtime for nonexistent instance {instance_id}!" - )) - })?; - let updated_recent_playtime = context.instance.recent_time_played; - let res = if updated_recent_playtime > 0 { - let modrinth_pack_version_id = modrinth_pack_version_id(&context.link); - let playtime_update_json = json!({ - "seconds": updated_recent_playtime, - "loader": context.applied_content_set.loader.as_str(), - "game_version": &context.applied_content_set.game_version, - "parent": modrinth_pack_version_id, - }); - let mut hashmap: HashMap = HashMap::new(); - - for (_, project) in get_projects(instance_id, None).await? { - if let Some(metadata) = project.modrinth { - hashmap.insert( - metadata.version_id.to_string(), - playtime_update_json.clone(), - ); - } - } - - let playtime_url = playtime_api_url(env!("MODRINTH_API_BASE_URL")); - fetch::post_json( - &playtime_url, - serde_json::to_value(hashmap)?, - &state.api_semaphore, - &state.pool, - ) - .await - } else { - Ok(()) - }; - - if res.is_ok() { - crate::state::instances::commands::mark_instance_playtime_submitted( - &context.instance.id, - updated_recent_playtime, - &state.pool, - ) - .await?; - } - - res -} - -#[cfg(test)] -mod tests { - use super::{modrinth_pack_version_id, playtime_api_url}; - use crate::state::InstanceLink; - - #[test] - fn playtime_parent_requires_an_explicit_modrinth_link() { - let modrinth = InstanceLink::ModrinthModpack { - project_id: "project".to_string(), - version_id: "version".to_string(), - }; - let curseforge = InstanceLink::CurseForgeModpack { - project_id: "123".to_string(), - version_id: "456".to_string(), - }; - let imported = InstanceLink::ImportedModpack { - project_id: Some("legacy-project".to_string()), - version_id: Some("legacy-version".to_string()), - name: None, - version_number: None, - filename: None, - }; - - assert_eq!(modrinth_pack_version_id(&modrinth), Some("version")); - assert_eq!(modrinth_pack_version_id(&curseforge), None); - assert_eq!(modrinth_pack_version_id(&imported), None); - } - - #[test] - fn playtime_url_has_a_single_path_separator() { - assert_eq!( - playtime_api_url("https://api.modrinth.com"), - "https://api.modrinth.com/analytics/playtime" - ); - assert_eq!( - playtime_api_url("https://api.modrinth.com/"), - "https://api.modrinth.com/analytics/playtime" - ); - } -} diff --git a/packages/app-lib/src/api/loader_metadata.rs b/packages/app-lib/src/api/loader_metadata.rs index facab4a..18203d2 100644 --- a/packages/app-lib/src/api/loader_metadata.rs +++ b/packages/app-lib/src/api/loader_metadata.rs @@ -1096,7 +1096,7 @@ async fn fetch_maven_metadata( fetch_semaphore: &FetchSemaphore, pool: &SqlitePool, ) -> crate::Result { - let bytes = fetch(url, None, None, None, fetch_semaphore, pool).await?; + let bytes = fetch(url, None, None, fetch_semaphore, pool).await?; let xml = std::str::from_utf8(&bytes).map_err(|error| { crate::ErrorKind::OtherError(format!( "Maven metadata at {url} was not UTF-8: {error}" @@ -1116,8 +1116,7 @@ async fn fetch_forge_maven_metadata( fetch_semaphore: &FetchSemaphore, pool: &SqlitePool, ) -> crate::Result { - let bytes = - fetch_official(url, None, None, None, fetch_semaphore, pool).await?; + let bytes = fetch_official(url, None, None, fetch_semaphore, pool).await?; let xml = std::str::from_utf8(&bytes).map_err(|error| { crate::ErrorKind::OtherError(format!( "Forge Maven metadata at {url} was not UTF-8: {error}" @@ -1651,15 +1650,9 @@ async fn resolve_installer_profile( state: &State, installer_url: &str, ) -> crate::Result { - let bytes = fetch( - installer_url, - None, - None, - None, - &state.api_semaphore, - &state.pool, - ) - .await?; + let bytes = + fetch(installer_url, None, None, &state.api_semaphore, &state.pool) + .await?; let installer_url = installer_url.to_string(); let parsed = tokio::task::spawn_blocking(move || { parse_installer(bytes.to_vec(), &installer_url) @@ -1702,7 +1695,6 @@ pub(crate) async fn ensure_installer_artifacts( &installer_url.client, None, None, - None, &state.api_semaphore, &state.pool, ) diff --git a/packages/app-lib/src/api/mod.rs b/packages/app-lib/src/api/mod.rs index a7f6633..191fd26 100644 --- a/packages/app-lib/src/api/mod.rs +++ b/packages/app-lib/src/api/mod.rs @@ -65,9 +65,9 @@ pub mod data { ManualDownloadOperationKind, ManualDownloadState, MemorySettings, ModLoader, ModrinthCredentials, Organization, OwnerType, PackMemberMaterializationState, PackMemberOverrideKind, - PendingManualDownload, PrivacySettings, ProcessMetadata, Project, - ProjectType, ProjectV3, SearchResult, SearchResults, SearchResultsV3, - Settings, ShaderRuntime, TeamMember, Theme, User, UserFriend, Version, + PendingManualDownload, ProcessMetadata, Project, ProjectType, + ProjectV3, SearchResult, SearchResults, SearchResultsV3, Settings, + ShaderRuntime, TeamMember, Theme, User, UserFriend, Version, WindowSize, }; pub use ariadne::users::UserStatus; diff --git a/packages/app-lib/src/api/pack/import/curseforge.rs b/packages/app-lib/src/api/pack/import/curseforge.rs index 17df160..9df8a73 100644 --- a/packages/app-lib/src/api/pack/import/curseforge.rs +++ b/packages/app-lib/src/api/pack/import/curseforge.rs @@ -117,7 +117,6 @@ pub async fn import_curseforge( &thumbnail_url, None, None, - None, &state.fetch_semaphore, &state.pool, ) diff --git a/packages/app-lib/src/api/pack/install_from.rs b/packages/app-lib/src/api/pack/install_from.rs index 7fca71d..53c812b 100644 --- a/packages/app-lib/src/api/pack/install_from.rs +++ b/packages/app-lib/src/api/pack/install_from.rs @@ -12,9 +12,8 @@ use crate::state::{ ModrinthVersionId, SideType, }; use crate::util::fetch::{ - ContentValidation, DownloadMeta, DownloadReason, DownloadRequest, - FetchProgressFn, Integrity, ResourceClass, download_to_path, fetch, - sha1_file_async, write_cached_icon, + ContentValidation, DownloadRequest, FetchProgressFn, Integrity, + ResourceClass, download_to_path, fetch, sha1_file_async, write_cached_icon, }; use path_util::SafeRelativeUtf8UnixPathBuf; use serde::{Deserialize, Serialize}; @@ -267,7 +266,6 @@ pub(crate) async fn generate_pack_from_version_id_with_reporter( title: String, icon_url: Option, instance_id: String, - reason: DownloadReason, reporter: InstallProgressReporter, ) -> crate::Result { let state = State::get().await?; @@ -340,22 +338,6 @@ pub(crate) async fn generate_pack_from_version_id_with_reporter( .join(&version_id) .join(file_name); - let metadata = - crate::api::instance::get(&instance_id) - .await? - .ok_or_else(|| { - crate::ErrorKind::InputError(format!( - "Unknown instance {instance_id}" - )) - })?; - - let download_meta = DownloadMeta { - reason, - game_version: metadata.applied_content_set.game_version.clone(), - loader: metadata.applied_content_set.loader.as_str().to_string(), - dependent_on: Some(version_id.clone()), - }; - let details = InstallPhaseDetails::Modpack { project_id: Some(project_id.clone()), version_id: Some(version_id.clone()), @@ -430,7 +412,6 @@ pub(crate) async fn generate_pack_from_version_id_with_reporter( ..Integrity::default() }) .with_h2_range_concurrency(16) - .with_download_meta(download_meta) .with_install_tracking( reporter.clone(), pack_path.display().to_string(), @@ -487,7 +468,6 @@ pub(crate) async fn generate_pack_from_version_id_with_reporter( &icon_url, None, None, - None, &state.fetch_semaphore, &state.pool, ) diff --git a/packages/app-lib/src/api/pack/install_mrpack.rs b/packages/app-lib/src/api/pack/install_mrpack.rs index 9690938..7de173b 100644 --- a/packages/app-lib/src/api/pack/install_mrpack.rs +++ b/packages/app-lib/src/api/pack/install_mrpack.rs @@ -23,8 +23,8 @@ use crate::state::{ Settings, SideType, }; use crate::util::fetch::{ - ContentValidation, DownloadMeta, DownloadReason, DownloadRequest, - Integrity, ResourceClass, download_to_path, sha1_file_async, + ContentValidation, DownloadRequest, Integrity, ResourceClass, + download_to_path, sha1_file_async, }; use crate::util::io; use async_zip::base::read::seek::ZipFileReader as SeekZipFileReader; @@ -219,7 +219,6 @@ fn missing_required_content_pause( struct ModpackContentInstallContext { instance_id: String, instance_full_path: PathBuf, - download_meta: DownloadMeta, pack_version_id: Option, pack_project_id: Option, reporter: InstallProgressReporter, @@ -689,7 +688,6 @@ where pub(crate) async fn install_zipped_mrpack_files_with_reporter( create_pack: CreatePack, ignore_lock: bool, - reason: DownloadReason, reporter: InstallProgressReporter, ) -> crate::Result { let state = &State::get().await?; @@ -806,21 +804,6 @@ pub(crate) async fn install_zipped_mrpack_files_with_reporter( ) .await?; - let metadata = - crate::api::instance::get(&instance_id) - .await? - .ok_or_else(|| { - crate::ErrorKind::InputError(format!( - "Unknown instance {instance_id}" - )) - })?; - let download_meta = DownloadMeta { - reason, - game_version: metadata.applied_content_set.game_version.clone(), - loader: metadata.applied_content_set.loader.as_str().to_string(), - dependent_on: version_id.clone(), - }; - let num_files = pack.files.len(); let content_total_bytes = pack .files @@ -892,7 +875,6 @@ pub(crate) async fn install_zipped_mrpack_files_with_reporter( let content_context = ModpackContentInstallContext { instance_id: instance_id.clone(), instance_full_path: instance_full_path.clone(), - download_meta, pack_version_id: version_id.clone(), pack_project_id: project_id.clone(), reporter: reporter.clone(), @@ -1191,9 +1173,6 @@ pub(crate) async fn install_zipped_mrpack_files_with_reporter( project.downloads.iter().skip(1).cloned(), ) .with_integrity(integrity) - .with_download_meta( - content_context.download_meta.clone(), - ) .with_segmented_download(true) .with_http1_segmented_download(false) .with_install_tracking( diff --git a/packages/app-lib/src/api/settings.rs b/packages/app-lib/src/api/settings.rs index 139fdcf..f0b60a6 100644 --- a/packages/app-lib/src/api/settings.rs +++ b/packages/app-lib/src/api/settings.rs @@ -3,10 +3,7 @@ pub use crate::util::download::DownloadEngine; pub use crate::{ State, - state::{ - DownloadSourceMode, Hooks, MemorySettings, PrivacySettings, Settings, - WindowSize, - }, + state::{DownloadSourceMode, Hooks, MemorySettings, Settings, WindowSize}, }; /// Gets entire settings @@ -21,10 +18,6 @@ pub async fn get() -> crate::Result { #[tracing::instrument] pub async fn set(mut settings: Settings) -> crate::Result<()> { let state = State::get().await?; - let current = Settings::get(&state.pool).await?; - settings.telemetry = current.telemetry; - settings.telemetry_consent_version = current.telemetry_consent_version; - settings.discord_rpc = current.discord_rpc; super::terracotta::validate_public_nodes( &settings.terracotta_public_nodes, )?; @@ -46,78 +39,6 @@ pub async fn set_download_engine(engine: DownloadEngine) -> crate::Result<()> { Ok(()) } -#[tracing::instrument] -pub async fn get_privacy() -> crate::Result { - let state = State::get().await?; - let settings = Settings::get(&state.pool).await?; - Ok(PrivacySettings { - telemetry: settings.telemetry, - discord_rpc: settings.discord_rpc, - consent_version: settings.telemetry_consent_version, - }) -} - -#[tracing::instrument] -pub async fn set_privacy( - privacy: PrivacySettings, -) -> crate::Result { - let state = State::get().await?; - let mut transaction = state.pool.begin().await?; - sqlx::query( - "UPDATE settings SET telemetry = ?, discord_rpc = ?, telemetry_consent_version = ? WHERE id = 0", - ) - .bind(privacy.telemetry) - .bind(privacy.discord_rpc) - .bind(privacy.consent_version) - .execute(&mut *transaction) - .await?; - sqlx::query("DELETE FROM telemetry_outbox") - .execute(&mut *transaction) - .await?; - transaction.commit().await?; - - if let Err(error) = - crate::telemetry::set_enabled(&state, privacy.telemetry).await - { - tracing::debug!(target: "theseus::telemetry", %error, "Failed to apply telemetry state"); - } - if let Err(error) = state.discord_rpc.clear_to_default(true).await { - tracing::debug!(target: "theseus::telemetry", %error, "Failed to apply Discord RPC state"); - } - get_privacy().await -} - -#[tracing::instrument] -pub async fn set_telemetry(enabled: bool) -> crate::Result { - let state = State::get().await?; - let mut transaction = state.pool.begin().await?; - sqlx::query("UPDATE settings SET telemetry = ? WHERE id = 0") - .bind(enabled) - .execute(&mut *transaction) - .await?; - sqlx::query("DELETE FROM telemetry_outbox") - .execute(&mut *transaction) - .await?; - transaction.commit().await?; - if let Err(error) = crate::telemetry::set_enabled(&state, enabled).await { - tracing::debug!(target: "theseus::telemetry", %error, "Failed to apply telemetry state"); - } - get_privacy().await -} - -#[tracing::instrument] -pub async fn set_discord_rpc(enabled: bool) -> crate::Result { - let state = State::get().await?; - sqlx::query("UPDATE settings SET discord_rpc = ? WHERE id = 0") - .bind(enabled) - .execute(&state.pool) - .await?; - if let Err(error) = state.discord_rpc.clear_to_default(true).await { - tracing::debug!(target: "theseus::telemetry", %error, "Failed to apply Discord RPC state"); - } - get_privacy().await -} - #[tracing::instrument] pub async fn cancel_directory_change( app_identifier: &str, diff --git a/packages/app-lib/src/error.rs b/packages/app-lib/src/error.rs index 2e2a158..5d85031 100644 --- a/packages/app-lib/src/error.rs +++ b/packages/app-lib/src/error.rs @@ -222,9 +222,6 @@ pub enum ErrorKind { #[error("Deserialization error: {0}")] DeserializationError(#[from] serde::de::value::Error), - - #[error("Discord IPC error: {0}")] - DiscordRichPresenceError(#[from] discord_rich_presence::error::Error), } #[derive(Debug)] diff --git a/packages/app-lib/src/install/runner.rs b/packages/app-lib/src/install/runner.rs index ca2ce91..d88a09c 100644 --- a/packages/app-lib/src/install/runner.rs +++ b/packages/app-lib/src/install/runner.rs @@ -28,7 +28,6 @@ use crate::state::{ LoaderComponent, LoaderComponentKind, LoaderComponentRole, ModLoader, State, }; -use crate::util::fetch::DownloadReason; use futures::stream::{FuturesUnordered, StreamExt}; use std::collections::{HashMap, HashSet}; use std::future::Future; @@ -1513,14 +1512,8 @@ async fn run_request( ) .await?; if let InstallExecutionOutcome::WaitingForUser(reason) = - install_pack( - job_id, - job_state, - location, - instance_id.clone(), - DownloadReason::Modpack, - ) - .await? + install_pack(job_id, job_state, location, instance_id.clone()) + .await? { return Ok(InstallExecutionOutcome::WaitingForUser(reason)); } @@ -1714,14 +1707,8 @@ async fn run_request( } }; if let InstallExecutionOutcome::WaitingForUser(reason) = - install_pack( - job_id, - job_state, - location, - instance_id.clone(), - DownloadReason::Modpack, - ) - .await? + install_pack(job_id, job_state, location, instance_id.clone()) + .await? { return Ok(InstallExecutionOutcome::WaitingForUser(reason)); } @@ -2973,13 +2960,8 @@ async fn stage_upgrade_content( let reporter = reporter.clone(); async move { let index = context.index; - let mutation = stage_one_upgrade_request( - instance_id, - context, - reporter, - state, - ) - .await?; + let mutation = + stage_one_upgrade_request(context, reporter, state).await?; Ok::<_, crate::Error>((index, mutation)) } }) @@ -3002,7 +2984,6 @@ where } async fn stage_one_upgrade_request( - instance_id: &str, context: UpgradeStagingRequest, reporter: Option, state: &State, @@ -3011,27 +2992,13 @@ async fn stage_one_upgrade_request( ContentProvider::Modrinth => StagedUpgradeDownload::Modrinth( match reporter.as_ref() { Some(reporter) => crate::state::instances::commands::download_project_version_with_reporter( - instance_id, &context.release_id, - if context.auto_dependency { - DownloadReason::Dependency - } else { - DownloadReason::Update - }, - None, reporter.clone(), state, ) .await?, None => crate::state::instances::commands::download_project_version( - instance_id, &context.release_id, - if context.auto_dependency { - DownloadReason::Dependency - } else { - DownloadReason::Update - }, - None, state, ) .await?, @@ -3739,7 +3706,6 @@ async fn remove_existing_pack_content( metadata.instance.name.clone(), None, instance_id.to_string(), - DownloadReason::Update, reporter, ) .await?; @@ -3799,7 +3765,6 @@ async fn install_pack( job_state: &mut InstallJobState, location: CreatePackLocation, instance_id: String, - reason: DownloadReason, ) -> crate::Result> { let reporter = InstallProgressReporter::new(job_id, job_state.clone()); reporter @@ -3831,7 +3796,6 @@ async fn install_pack( title, icon_url, instance_id.clone(), - reason, reporter.clone(), ) .await? @@ -3882,13 +3846,9 @@ async fn install_pack( } }; - let outcome = install_zipped_mrpack_files_with_reporter( - create_pack, - false, - reason, - reporter, - ) - .await?; + let outcome = + install_zipped_mrpack_files_with_reporter(create_pack, false, reporter) + .await?; Ok(match outcome { MrpackInstallOutcome::Completed(_) => { InstallExecutionOutcome::Completed(()) @@ -4056,7 +4016,6 @@ async fn install_local_pack_file( match install_zipped_mrpack_files_with_reporter( create_pack, false, - DownloadReason::Modpack, reporter, ) .await? diff --git a/packages/app-lib/src/launcher/mod.rs b/packages/app-lib/src/launcher/mod.rs index 5a51adb..dc56b8b 100644 --- a/packages/app-lib/src/launcher/mod.rs +++ b/packages/app-lib/src/launcher/mod.rs @@ -2389,11 +2389,6 @@ pub async fn launch_minecraft( ) .await?; - let _ = state - .discord_rpc - .set_activity(&format!("Playing {}", instance.name), true) - .await; - // The launcher log must land where the game and log browser read it. The // resolved directory is PCL's PathIndie equivalent for direct links. let logs_folder = state.directories.game_logs_dir(&instance_path); diff --git a/packages/app-lib/src/lib.rs b/packages/app-lib/src/lib.rs index d8df7b9..3b9a628 100644 --- a/packages/app-lib/src/lib.rs +++ b/packages/app-lib/src/lib.rs @@ -21,7 +21,6 @@ mod logger; pub mod mod_metadata; mod state; pub mod storage; -pub mod telemetry; pub use api::*; pub use error::*; @@ -37,7 +36,7 @@ pub use state::db::{ }; pub use state::{DirectoryInfo, State}; pub use storage::*; -pub use util::fetch::{DownloadReason, build_proxied_client}; +pub use util::fetch::build_proxied_client; pub use util::file_lock::{LockingProcess, get_locking_processes}; pub use util::platform::is_process_elevated; pub use util::proxy::{ProxyConfig, ProxyMode, ProxyTestResult}; diff --git a/packages/app-lib/src/state/discord.rs b/packages/app-lib/src/state/discord.rs deleted file mode 100644 index 13caa60..0000000 --- a/packages/app-lib/src/state/discord.rs +++ /dev/null @@ -1,238 +0,0 @@ -use std::sync::{ - Arc, Mutex, TryLockError, atomic::AtomicBool, atomic::Ordering, -}; -use std::time::Duration; - -use discord_rich_presence::{ - DiscordIpc, DiscordIpcClient, - activity::{Activity, Assets}, -}; -use tokio::sync::RwLock; -use tokio::task::JoinHandle; - -use crate::State; - -pub struct DiscordGuard { - client: Arc>, - connected: Arc, - launcher_activity: Arc>, -} - -const DISCORD_IPC_TIMEOUT: Duration = Duration::from_secs(2); - -async fn await_ipc_task( - operation: &'static str, - timeout: Duration, - task: JoinHandle, -) -> Option { - match tokio::time::timeout(timeout, task).await { - Ok(Ok(result)) => Some(result), - Ok(Err(error)) => { - tracing::warn!(%error, operation, "Discord IPC worker failed"); - None - } - Err(_) => { - tracing::warn!(operation, "Discord IPC operation timed out"); - None - } - } -} - -impl DiscordGuard { - /// Initialize discord IPC client, and attempt to connect to it - /// If it fails, it will still return a DiscordGuard, but the client will be unconnected - pub fn init() -> crate::Result { - let dipc = DiscordIpcClient::new("1533353147349864458"); - - Ok(DiscordGuard { - client: Arc::new(Mutex::new(dipc)), - connected: Arc::new(AtomicBool::new(false)), - launcher_activity: Arc::new(RwLock::new("Idling...".to_string())), - }) - } - - async fn run_ipc( - &self, - operation: &'static str, - connect_if_needed: bool, - action: F, - ) where - F: FnOnce(&mut DiscordIpcClient) -> crate::Result<()> + Send + 'static, - { - let client = self.client.clone(); - let connected = self.connected.clone(); - let task = tokio::task::spawn_blocking(move || { - let mut client = match client.try_lock() { - Ok(client) => client, - Err(TryLockError::WouldBlock) => { - tracing::warn!( - operation, - "Discord IPC client is busy; skipping activity update" - ); - return; - } - Err(TryLockError::Poisoned(error)) => { - tracing::warn!( - operation, - "Discord IPC client lock was poisoned; recovering" - ); - error.into_inner() - } - }; - - if !connected.load(Ordering::Relaxed) { - if !connect_if_needed { - return; - } - if client.connect().is_err() { - return; - } - connected.store(true, Ordering::Relaxed); - } - - if let Err(error) = action(&mut client) { - connected.store(false, Ordering::Relaxed); - tracing::warn!(%error, operation, "Discord IPC operation failed"); - } - }); - - let _ = await_ipc_task(operation, DISCORD_IPC_TIMEOUT, task).await; - } - - /// Set the activity to the given message - /// First checks if discord is disabled, and if so, clear the activity instead - pub async fn set_activity( - &self, - msg: &str, - reconnect_if_fail: bool, - ) -> crate::Result<()> { - // Check if discord is disabled, and if so, clear the activity instead - let state = State::get().await?; - let settings = crate::state::Settings::get(&state.pool).await?; - if !settings.discord_rpc { - Ok(self.clear_activity(true).await?) - } else { - Ok(self.force_set_activity(msg, reconnect_if_fail).await?) - } - } - - pub async fn set_launcher_activity( - &self, - msg: &str, - reconnect_if_fail: bool, - ) -> crate::Result<()> { - *self.launcher_activity.write().await = msg.to_string(); - - let state = State::get().await?; - if state.process_manager.get_all().is_empty() { - self.set_activity(msg, reconnect_if_fail).await?; - } - Ok(()) - } - - /// Sets the activity to the given message, regardless of if discord is disabled or offline - /// Should not be used except for in the above method, or if it is already known that discord is enabled (specifically for state initialization) and we are connected to the internet - pub async fn force_set_activity( - &self, - msg: &str, - reconnect_if_fail: bool, - ) -> crate::Result<()> { - let msg = msg.to_string(); - self.run_ipc("set activity", true, move |client| { - let activity = Activity::new().state(&msg).assets( - Assets::new() - .large_image("modrinth_simple") - .large_text("Modrinth Logo"), - ); - let result = client.set_activity(activity.clone()); - - if reconnect_if_fail && result.is_err() { - client.reconnect()?; - client.set_activity(activity)?; - } else { - result?; - } - Ok(()) - }) - .await; - - Ok(()) - } - - /// Clear the activity entirely ('disabling' the RPC until the next set_activity) - pub async fn clear_activity( - &self, - reconnect_if_fail: bool, - ) -> crate::Result<()> { - self.run_ipc("clear activity", false, move |client| { - let result = client.clear_activity(); - - if reconnect_if_fail && result.is_err() { - client.reconnect()?; - client.clear_activity()?; - } else { - result?; - } - Ok(()) - }) - .await; - Ok(()) - } - - /// Clear the activity, but if there is a running profile, set the activity to that instead - pub async fn clear_to_default( - &self, - reconnect_if_fail: bool, - ) -> crate::Result<()> { - let state = State::get().await?; - - let settings = crate::state::Settings::get(&state.pool).await?; - if !settings.discord_rpc { - println!("Discord is disabled, clearing activity"); - return self.clear_activity(true).await; - } - - let running_instances = state.process_manager.get_all(); - if let Some(existing_child) = running_instances.first() { - self.set_activity( - &format!("Playing {}", existing_child.instance_name), - reconnect_if_fail, - ) - .await?; - } else { - let launcher_activity = self.launcher_activity.read().await.clone(); - self.set_activity(&launcher_activity, reconnect_if_fail) - .await?; - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::await_ipc_task; - use std::time::Duration; - - #[tokio::test] - async fn ipc_task_returns_completed_result() { - let task = tokio::task::spawn_blocking(|| 42); - - assert_eq!( - await_ipc_task("test", Duration::from_secs(1), task).await, - Some(42) - ); - } - - #[tokio::test] - async fn ipc_task_stops_waiting_after_timeout() { - let task = tokio::task::spawn_blocking(|| { - std::thread::sleep(Duration::from_millis(100)); - 42 - }); - - assert_eq!( - await_ipc_task("test", Duration::from_millis(10), task).await, - None - ); - } -} diff --git a/packages/app-lib/src/state/friends.rs b/packages/app-lib/src/state/friends.rs index 9e59feb..d386c5e 100644 --- a/packages/app-lib/src/state/friends.rs +++ b/packages/app-lib/src/state/friends.rs @@ -357,7 +357,6 @@ impl FriendsSocket { None, None, None, - None, Some("/v3/friend/:user_id"), semaphore, exec, @@ -391,7 +390,6 @@ impl FriendsSocket { None, None, None, - None, Some("/v3/friend/:user_id"), semaphore, exec, diff --git a/packages/app-lib/src/state/instances/commands/apply_content_install.rs b/packages/app-lib/src/state/instances/commands/apply_content_install.rs index 3d9bc53..c245521 100644 --- a/packages/app-lib/src/state/instances/commands/apply_content_install.rs +++ b/packages/app-lib/src/state/instances/commands/apply_content_install.rs @@ -18,8 +18,8 @@ use crate::state::{ Version, cache_file_hash, cache_file_hash_metadata, }; use crate::util::fetch::{ - self, ContentValidation, DownloadMeta, DownloadReason, DownloadRequest, - Integrity, ResourceClass, download_to_path, + self, ContentValidation, DownloadRequest, Integrity, ResourceClass, + download_to_path, }; use crate::util::io; use crate::util::io::io_error_with_lock_info; @@ -307,7 +307,6 @@ pub(crate) async fn install_resolved_content_plan_with_reporter( add_resolved_content_with_progress( instance_id, &plan.primary, - DownloadReason::Standalone, false, primary_progress, state, @@ -332,7 +331,6 @@ pub(crate) async fn install_resolved_content_plan_with_reporter( add_resolved_content_with_progress( instance_id, dependency, - DownloadReason::Dependency, true, dependency_progress, state, @@ -424,8 +422,6 @@ pub(crate) async fn switch_project_version_with_dependencies( let mut new_path = add_project_from_version( instance_id, &plan.primary.version_id, - DownloadReason::Update, - None, ContentSourceKind::Local, ownership_kind, state, @@ -442,14 +438,7 @@ pub(crate) async fn switch_project_version_with_dependencies( installed_paths.push(new_path.clone()); for dependency in &plan.dependencies { installed_paths.push( - add_resolved_content( - instance_id, - dependency, - DownloadReason::Dependency, - true, - state, - ) - .await?, + add_resolved_content(instance_id, dependency, true, state).await?, ); } persist_resolved_plan_dependency_edges( @@ -474,14 +463,12 @@ pub(crate) async fn switch_project_version_with_dependencies( pub(crate) async fn add_resolved_content( instance_id: &str, content: &ResolvedContent, - reason: DownloadReason, auto_dependency: bool, state: &State, ) -> crate::Result { add_resolved_content_with_progress( instance_id, content, - reason, auto_dependency, None, state, @@ -492,7 +479,6 @@ pub(crate) async fn add_resolved_content( async fn add_resolved_content_with_progress( instance_id: &str, content: &ResolvedContent, - reason: DownloadReason, auto_dependency: bool, progress: Option, state: &State, @@ -500,8 +486,6 @@ async fn add_resolved_content_with_progress( let path = add_project_from_version_with_progress( instance_id, &content.version_id, - reason, - content.dependent_on_version_id.clone(), ContentSourceKind::Local, ContentOwnershipKind::UserAdded, progress, @@ -536,15 +520,8 @@ pub(crate) async fn install_resolved_dependency( content: &ResolvedContent, state: &State, ) -> crate::Result { - add_resolved_content_with_progress( - instance_id, - content, - DownloadReason::Dependency, - true, - None, - state, - ) - .await + add_resolved_content_with_progress(instance_id, content, true, None, state) + .await } pub(crate) async fn persist_resolved_plan_dependency_edges( @@ -728,8 +705,6 @@ pub(crate) async fn resolve_content_scope( pub(crate) async fn add_project_from_version( instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, source_kind: ContentSourceKind, ownership_kind: ContentOwnershipKind, state: &State, @@ -737,8 +712,6 @@ pub(crate) async fn add_project_from_version( add_project_from_version_with_progress( instance_id, version_id, - reason, - dependent_on_version_id, source_kind, ownership_kind, None, @@ -751,22 +724,14 @@ pub(crate) async fn add_project_from_version( pub(crate) async fn add_project_from_version_with_progress( instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, source_kind: ContentSourceKind, ownership_kind: ContentOwnershipKind, progress: Option, state: &State, ) -> crate::Result { - let downloaded = download_project_version_with_progress( - instance_id, - version_id, - reason, - dependent_on_version_id, - progress, - state, - ) - .await?; + let downloaded = + download_project_version_with_progress(version_id, progress, state) + .await?; add_downloaded_project_version( instance_id, @@ -779,21 +744,10 @@ pub(crate) async fn add_project_from_version_with_progress( } pub(crate) async fn download_project_version( - instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, state: &State, ) -> crate::Result { - download_project_version_with_progress( - instance_id, - version_id, - reason, - dependent_on_version_id, - None, - state, - ) - .await + download_project_version_with_progress(version_id, None, state).await } /// Progress context for one file inside a multi-file content install. @@ -807,38 +761,21 @@ pub(crate) struct ResolvedContentDownloadProgress { } pub(crate) async fn download_project_version_with_progress( - instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, progress: Option, state: &State, ) -> crate::Result { - download_project_version_with_reporting( - instance_id, - version_id, - reason, - dependent_on_version_id, - progress, - None, - state, - ) - .await + download_project_version_with_reporting(version_id, progress, None, state) + .await } pub(crate) async fn download_project_version_with_reporter( - instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, reporter: crate::install::InstallProgressReporter, state: &State, ) -> crate::Result { download_project_version_with_reporting( - instance_id, version_id, - reason, - dependent_on_version_id, None, Some(reporter), state, @@ -847,26 +784,15 @@ pub(crate) async fn download_project_version_with_reporter( } async fn download_project_version_with_reporting( - instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, progress: Option, reporter: Option, state: &State, ) -> crate::Result { - let prepared = prepare_version_download( - instance_id, - version_id, - reason, - dependent_on_version_id, - state, - ) - .await?; + let prepared = prepare_version_download(version_id, state).await?; let mut request = DownloadRequest::new(&prepared.url, ResourceClass::Modrinth) - .with_integrity(prepared.integrity) - .with_download_meta(prepared.download_meta); + .with_integrity(prepared.integrity); let tracking_reporter = progress .as_ref() .map(|progress| progress.reporter.clone()) @@ -961,7 +887,6 @@ async fn download_project_version_with_reporting( struct PreparedVersionDownload { url: String, path: PathBuf, - download_meta: DownloadMeta, integrity: Integrity, file_name: String, sha1: Option, @@ -973,22 +898,9 @@ struct PreparedVersionDownload { /// Resolves the content scope and version metadata for a download and /// validates the target path, without touching the network. async fn prepare_version_download( - instance_id: &str, version_id: &str, - reason: DownloadReason, - dependent_on_version_id: Option, state: &State, ) -> crate::Result { - let scope = resolve_content_scope(instance_id, None, state).await?; - let content_set = - content_rows::get_content_set(&scope.content_set_id, &state.pool) - .await? - .ok_or_else(|| { - crate::ErrorKind::InputError(format!( - "Unknown content set {}", - scope.content_set_id - )) - })?; let version = CachedEntry::get_version( &ModrinthVersionId::new(version_id.to_string())?, None, @@ -1011,12 +923,6 @@ async fn prepare_version_download( "No files for input version present!".to_string(), ) })?; - let download_meta = DownloadMeta { - reason, - game_version: content_set.game_version, - loader: content_set.loader.as_str().to_string(), - dependent_on: dependent_on_version_id, - }; let file_name_path = Path::new(&file.filename); if file_name_path.as_os_str().is_empty() || file_name_path.is_absolute() @@ -1057,7 +963,6 @@ async fn prepare_version_download( Ok(PreparedVersionDownload { url: file.url.clone(), path, - download_meta, integrity, file_name: file.filename.clone(), sha1: file.hashes.get("sha1").cloned(), diff --git a/packages/app-lib/src/state/instances/commands/apply_content_update.rs b/packages/app-lib/src/state/instances/commands/apply_content_update.rs index 41b02b0..325b8ea 100644 --- a/packages/app-lib/src/state/instances/commands/apply_content_update.rs +++ b/packages/app-lib/src/state/instances/commands/apply_content_update.rs @@ -6,7 +6,6 @@ use crate::state::{ CacheBehaviour, CachedEntry, ContentProviderRef, Dependency, DependencyType, ModrinthVersionId, ProjectType, State, Version, }; -use crate::util::fetch::DownloadReason; use futures::stream::{FuturesUnordered, StreamExt}; use std::cmp::Reverse; use std::collections::{HashMap, HashSet}; @@ -31,7 +30,6 @@ struct BulkUpdatePlan { struct PlannedProjectUpdate { relative_path: String, project_id: String, - current_version_id: String, update_version_id: String, } @@ -107,7 +105,6 @@ async fn apply_content_update( let mut new_path = match update { ContentUpdate::Modrinth { project_id, - current_version_id, update_version_id, .. } => { @@ -149,8 +146,6 @@ async fn apply_content_update( add_project_from_version( instance_id, &plan.primary.version_id, - DownloadReason::Update, - Some(current_version_id.to_string()), ContentSourceKind::Local, ownership_kind, state, @@ -159,14 +154,8 @@ async fn apply_content_update( ); for dependency in &plan.dependencies { paths.push( - add_resolved_content( - instance_id, - dependency, - DownloadReason::Dependency, - true, - state, - ) - .await?, + add_resolved_content(instance_id, dependency, true, state) + .await?, ); } persist_resolved_plan_dependency_edges( @@ -449,10 +438,7 @@ async fn download_planned_projects( match download { PlannedDownload::ProjectUpdate(update) => { let downloaded = download_project_version( - instance_id, &update.update_version_id, - DownloadReason::Update, - Some(update.current_version_id.clone()), state, ) .await?; @@ -462,14 +448,9 @@ async fn download_planned_projects( )) } PlannedDownload::DependencyAddition(dependency) => { - let downloaded = download_project_version( - instance_id, - &dependency.version_id, - DownloadReason::Dependency, - Some(dependency.parent_version_id.clone()), - state, - ) - .await?; + let downloaded = + download_project_version(&dependency.version_id, state) + .await?; Ok::<_, crate::Error>( DownloadedBulkProject::DependencyAddition( @@ -636,11 +617,10 @@ async fn plan_bulk_update( let project_updates = updates .into_iter() .filter_map(|update| { - let (project_id, current, target) = update.modrinth_ids()?; + let (project_id, _, target) = update.modrinth_ids()?; Some(PlannedProjectUpdate { relative_path: update.relative_path().to_string(), project_id: project_id.to_string(), - current_version_id: current.to_string(), update_version_id: target.to_string(), }) }) diff --git a/packages/app-lib/src/state/instances/commands/create_instance.rs b/packages/app-lib/src/state/instances/commands/create_instance.rs index 92b3189..95bd2b9 100644 --- a/packages/app-lib/src/state/instances/commands/create_instance.rs +++ b/packages/app-lib/src/state/instances/commands/create_instance.rs @@ -294,15 +294,8 @@ async fn fetch_icon_bytes( return Ok(response.bytes().await?); } - fetch::fetch( - icon_url, - None, - None, - None, - &state.fetch_semaphore, - &state.pool, - ) - .await + fetch::fetch(icon_url, None, None, &state.fetch_semaphore, &state.pool) + .await } fn is_direct_cdn_icon_url(url: &str) -> bool { diff --git a/packages/app-lib/src/state/instances/commands/launch_context.rs b/packages/app-lib/src/state/instances/commands/launch_context.rs index e373b97..2884177 100644 --- a/packages/app-lib/src/state/instances/commands/launch_context.rs +++ b/packages/app-lib/src/state/instances/commands/launch_context.rs @@ -507,47 +507,6 @@ pub(crate) async fn add_instance_recent_playtime( Ok(()) } -pub(crate) async fn mark_instance_playtime_submitted( - instance_id: &str, - recent_time_played: u64, - pool: &SqlitePool, -) -> crate::Result<()> { - if recent_time_played == 0 { - return Ok(()); - } - - let recent_time_played = - playtime_to_storage(recent_time_played, "recent_time_played")?; - let max_playtime = i64::MAX; - let max_playtime_before_increment = max_playtime - recent_time_played; - let modified = Utc::now().timestamp(); - - sqlx::query!( - " - UPDATE instances - SET - submitted_time_played = CASE - WHEN submitted_time_played < 0 THEN ? - WHEN submitted_time_played > ? THEN ? - ELSE submitted_time_played + ? - END, - recent_time_played = 0, - modified = ? - WHERE id = ? - ", - recent_time_played, - max_playtime_before_increment, - max_playtime, - recent_time_played, - modified, - instance_id, - ) - .execute(pool) - .await?; - - Ok(()) -} - #[cfg(test)] mod tests { use chrono::{TimeZone, Utc}; diff --git a/packages/app-lib/src/state/instances/commands/list_content.rs b/packages/app-lib/src/state/instances/commands/list_content.rs index c5de1e7..e8bec25 100644 --- a/packages/app-lib/src/state/instances/commands/list_content.rs +++ b/packages/app-lib/src/state/instances/commands/list_content.rs @@ -20,8 +20,8 @@ use crate::state::{ ReleaseChannel, TeamMember, Version, VersionV3, }; use crate::util::fetch::{ - ContentValidation, DownloadMeta, DownloadReason, DownloadRequest, - FetchSemaphore, Integrity, ResourceClass, download_to_path, sha1_async, + ContentValidation, DownloadRequest, FetchSemaphore, Integrity, + ResourceClass, download_to_path, sha1_async, }; use async_zip::tokio::read::fs::ZipFileReader; use dashmap::DashMap; @@ -507,7 +507,6 @@ pub(crate) async fn list_linked_modpack_content( }; let ids = match get_modpack_identifiers( version_id, - &resolved.content_set, &state.pool, &state.api_semaphore, ) @@ -2520,7 +2519,6 @@ async fn get_cached_modpack_identifiers( async fn get_modpack_identifiers( version_id: &str, - content_set: &ContentSet, pool: &SqlitePool, fetch_semaphore: &FetchSemaphore, ) -> crate::Result { @@ -2585,12 +2583,6 @@ async fn get_modpack_identifiers( "No files found for modpack version {version_id}" )) })?; - let download_meta = DownloadMeta { - reason: DownloadReason::Modpack, - game_version: content_set.game_version.clone(), - loader: content_set.loader.as_str().to_string(), - dependent_on: Some(version_id.to_string()), - }; let state = State::get().await?; let file_name = Path::new(&primary_file.filename); if file_name.components().count() != 1 @@ -2619,8 +2611,7 @@ async fn get_modpack_identifiers( sha512: primary_file.hashes.get("sha512").cloned(), content: ContentValidation::Jar, ..Integrity::default() - }) - .with_download_meta(download_meta), + }), &pack_path, &state.download_semaphore, pool, diff --git a/packages/app-lib/src/state/legacy_converter.rs b/packages/app-lib/src/state/legacy_converter.rs index 008bea2..64453f3 100644 --- a/packages/app-lib/src/state/legacy_converter.rs +++ b/packages/app-lib/src/state/legacy_converter.rs @@ -61,8 +61,6 @@ where settings.collapsed_navigation = legacy_settings.collapsed_navigation; settings.advanced_rendering = legacy_settings.advanced_rendering; settings.native_decorations = legacy_settings.native_decorations; - settings.telemetry = !legacy_settings.opt_out_analytics; - settings.discord_rpc = !legacy_settings.disable_discord_rpc; settings.developer_mode = legacy_settings.developer_mode; settings.onboarded = legacy_settings.fully_onboarded; settings.extra_launch_args = legacy_settings.custom_java_args; @@ -660,8 +658,6 @@ struct LegacySettings { pub max_concurrent_writes: usize, pub collapsed_navigation: bool, #[serde(default)] - pub disable_discord_rpc: bool, - #[serde(default)] pub hide_on_process: bool, #[serde(default)] pub native_decorations: bool, @@ -670,8 +666,6 @@ struct LegacySettings { #[serde(default)] pub developer_mode: bool, #[serde(default)] - pub opt_out_analytics: bool, - #[serde(default)] pub advanced_rendering: bool, #[serde(default)] pub fully_onboarded: bool, diff --git a/packages/app-lib/src/state/mod.rs b/packages/app-lib/src/state/mod.rs index 8756ce7..626b26a 100644 --- a/packages/app-lib/src/state/mod.rs +++ b/packages/app-lib/src/state/mod.rs @@ -42,9 +42,6 @@ pub use self::java_globals::*; mod discovered_javas; pub use self::discovered_javas::*; -mod discord; -pub use self::discord::*; - mod minecraft_auth; pub use self::minecraft_auth::*; @@ -124,9 +121,6 @@ pub struct State { pub(crate) install_job_operation_locks: DashMap>>, - /// Discord RPC - pub discord_rpc: DiscordGuard, - /// Process manager pub process_manager: ProcessManager, @@ -501,8 +495,6 @@ impl State { concurrency_state.run_auto_concurrency_controller().await; }); - crate::telemetry::start(Arc::clone(state)); - tokio::task::spawn(async move { crate::google_ip::preload().await; }); @@ -521,14 +513,13 @@ impl State { .await; let res = tokio::try_join!( - state.discord_rpc.clear_to_default(true), instances::refresh_all_instances(), Settings::migrate(&state.pool), ModrinthCredentials::refresh_all(), ); if let Err(e) = res { - tracing::error!("Error running discord RPC: {e}"); + tracing::error!("Error refreshing startup state: {e}"); } // Axolotl does not connect to Modrinth's private friends socket. @@ -861,8 +852,6 @@ impl State { let directories = DirectoryInfo::init(settings.custom_dir, &app_identifier).await?; - let discord_rpc = DiscordGuard::init()?; - tracing::info!("Initializing file watcher"); let file_watcher = instances::watcher::init_watcher().await?; @@ -915,7 +904,6 @@ impl State { install_db_semaphore: Semaphore::new(1), install_job_cancellations: DashMap::new(), install_job_operation_locks: DashMap::new(), - discord_rpc, process_manager, friends_socket, restart_after_pending_update: AtomicBool::new(false), @@ -983,7 +971,6 @@ pub(crate) async fn test_state( install_db_semaphore: Semaphore::new(1), install_job_cancellations: DashMap::new(), install_job_operation_locks: DashMap::new(), - discord_rpc: DiscordGuard::init()?, process_manager: ProcessManager::new(), friends_socket: FriendsSocket::new(), restart_after_pending_update: AtomicBool::new(false), diff --git a/packages/app-lib/src/state/mr_auth.rs b/packages/app-lib/src/state/mr_auth.rs index 09b735e..50e4102 100644 --- a/packages/app-lib/src/state/mr_auth.rs +++ b/packages/app-lib/src/state/mr_auth.rs @@ -35,7 +35,6 @@ impl ModrinthCredentials { None, Some(("Authorization", &*creds.session)), None, - None, Some("/v2/session/refresh"), semaphore, exec, @@ -228,7 +227,6 @@ async fn fetch_info( None, Some(("Authorization", token)), None, - None, Some("/v2/user"), semaphore, exec, diff --git a/packages/app-lib/src/state/process.rs b/packages/app-lib/src/state/process.rs index 11a2a80..8c6f2bb 100644 --- a/packages/app-lib/src/state/process.rs +++ b/packages/app-lib/src/state/process.rs @@ -1194,25 +1194,6 @@ impl Process { record_post_upgrade_launch_best_effort(&instance_id, clean_launch) .await; - // Publish play time update - // Allow failure, it will be stored locally and sent next time - // Sent in another thread as first call may take a couple seconds and hold up process ending - let playtime_instance_id = instance_id.clone(); - tokio::spawn(async move { - if let Err(e) = - crate::api::instance::try_update_playtime_by_instance_id( - &playtime_instance_id, - ) - .await - { - tracing::warn!( - "Failed to update playtime for instance {}: {}", - playtime_instance_id, - e - ); - } - }); - let log_path = logs_folder.join(LAUNCHER_LOG_PATH); if log_path.exists() @@ -1248,8 +1229,6 @@ impl Process { ) .await?; - let _ = state.discord_rpc.clear_to_default(true).await; - if mc_exit_status.success() { // We do not wait on the post exist command to finish running! We let it spawn + run on its own. // This behaviour may be changed in the future diff --git a/packages/app-lib/src/state/settings.rs b/packages/app-lib/src/state/settings.rs index 03d3555..ed253f7 100644 --- a/packages/app-lib/src/state/settings.rs +++ b/packages/app-lib/src/state/settings.rs @@ -154,10 +154,6 @@ pub struct Settings { #[serde(default = "default_terracotta_public_nodes")] pub terracotta_public_nodes: Vec, - pub telemetry: bool, - #[serde(default)] - pub telemetry_consent_version: u32, - pub discord_rpc: bool, #[serde(skip, default)] pub personalized_ads: bool, @@ -190,13 +186,6 @@ pub struct Settings { pub version: usize, } -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] -pub struct PrivacySettings { - pub telemetry: bool, - pub discord_rpc: bool, - pub consent_version: u32, -} - fn default_true() -> bool { true } @@ -330,9 +319,6 @@ impl Settings { .as_ref() .and_then(|value| serde_json::from_str(value).ok()) .unwrap_or_else(default_terracotta_public_nodes), - telemetry: res.telemetry == 1, - telemetry_consent_version: res.telemetry_consent_version as u32, - discord_rpc: res.discord_rpc == 1, developer_mode: res.developer_mode == 1, personalized_ads: res.personalized_ads == 1, onboarded: res.onboarded == 1, @@ -521,9 +507,9 @@ impl Settings { self.collapsed_navigation, self.advanced_rendering, self.native_decorations, - self.discord_rpc, + false, self.developer_mode, - self.telemetry, + false, self.personalized_ads, self.onboarded, extra_launch_args, @@ -573,7 +559,7 @@ impl Settings { home_widgets, mojang_auth_source, terracotta_public_nodes, - self.telemetry_consent_version, + 0_i64, ) .execute(exec) .await?; @@ -1355,16 +1341,20 @@ mod tests { } #[tokio::test] - async fn telemetry_schema_migrates_fresh_and_existing_settings_databases() { + async fn removed_data_collection_schema_is_cleaned_up() { let fresh = sqlx::sqlite::SqlitePoolOptions::new() .max_connections(1) .connect("sqlite::memory:") .await .unwrap(); sqlx::migrate!().run(&fresh).await.unwrap(); - let settings = Settings::get(&fresh).await.unwrap(); - assert!(!settings.telemetry); - assert_eq!(settings.telemetry_consent_version, 0); + let telemetry_tables = sqlx::query_scalar::<_, String>( + "SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'telemetry_%'", + ) + .fetch_all(&fresh) + .await + .unwrap(); + assert!(telemetry_tables.is_empty()); assert!( sqlx::query("PRAGMA foreign_key_check") .fetch_all(&fresh) @@ -1372,44 +1362,5 @@ mod tests { .unwrap() .is_empty() ); - - let upgrade = sqlx::sqlite::SqlitePoolOptions::new() - .max_connections(1) - .connect("sqlite::memory:") - .await - .unwrap(); - sqlx::query( - "CREATE TABLE settings (id INTEGER PRIMARY KEY CHECK (id = 0), telemetry INTEGER NOT NULL DEFAULT 0, discord_rpc INTEGER NOT NULL DEFAULT 1)", - ) - .execute(&upgrade) - .await - .unwrap(); - sqlx::query( - "INSERT INTO settings (id, telemetry, discord_rpc) VALUES (0, 0, 1)", - ) - .execute(&upgrade) - .await - .unwrap(); - sqlx::raw_sql(include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/migrations/20260814120000_telemetry.sql" - ))) - .execute(&upgrade) - .await - .unwrap(); - let consent_version = sqlx::query_scalar::<_, i64>( - "SELECT telemetry_consent_version FROM settings WHERE id = 0", - ) - .fetch_one(&upgrade) - .await - .unwrap(); - assert_eq!(consent_version, 0); - assert!( - sqlx::query("PRAGMA foreign_key_check") - .fetch_all(&upgrade) - .await - .unwrap() - .is_empty() - ); } } diff --git a/packages/app-lib/src/telemetry.rs b/packages/app-lib/src/telemetry.rs deleted file mode 100644 index a1b8294..0000000 --- a/packages/app-lib/src/telemetry.rs +++ /dev/null @@ -1,391 +0,0 @@ -use std::fmt::Write as _; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, OnceLock}; -use std::time::Duration; - -use chrono::{SecondsFormat, Utc}; -use serde_json::{Value, json}; -use sha2::{Digest, Sha256}; -use sqlx::Row; -use uuid::Uuid; - -use crate::State; - -const ENDPOINT: &str = "https://telemetry.axlmc.org/v1/batch"; -const MAX_OUTBOX_EVENTS: i64 = 100; -const MAX_OUTBOX_BYTES: i64 = 2 * 1024 * 1024; -const MAX_EVENT_AGE_SECONDS: i64 = 7 * 24 * 60 * 60; -const MAX_BATCH_EVENTS: i64 = 10; -const MAX_BATCH_BYTES: usize = 60 * 1024; - -static STARTED: AtomicBool = AtomicBool::new(false); -static WAKE_TX: OnceLock> = OnceLock::new(); - -pub(crate) fn start(state: Arc) { - if STARTED.swap(true, Ordering::AcqRel) { - return; - } - - let (wake_tx, mut wake_rx) = tokio::sync::mpsc::channel(1); - let _ = WAKE_TX.set(wake_tx); - tokio::spawn(async move { - loop { - let client = match crate::util::fetch::configured_client().await { - Ok(client) => client, - Err(error) => { - tracing::debug!(target: "theseus::telemetry", %error, "Telemetry client configuration failed"); - tokio::time::sleep(Duration::from_secs(60)).await; - continue; - } - }; - if let Err(error) = run_cycle(&state, &client).await { - tracing::debug!(target: "theseus::telemetry", %error, "Telemetry cycle failed"); - } - - tokio::select! { - _ = tokio::time::sleep(Duration::from_secs(60)) => {}, - _ = wake_rx.recv() => {}, - } - } - }); -} - -pub async fn set_enabled(state: &State, enabled: bool) -> crate::Result<()> { - sqlx::query("DELETE FROM telemetry_outbox") - .execute(&state.pool) - .await?; - - if enabled { - ensure_identity(&state.pool).await?; - enqueue_heartbeat(state).await?; - wake(); - } - Ok(()) -} - -pub fn notify_online() { - wake(); -} - -async fn run_cycle( - state: &State, - client: &reqwest::Client, -) -> crate::Result<()> { - if !is_enabled(state).await? { - sqlx::query("DELETE FROM telemetry_outbox") - .execute(&state.pool) - .await?; - return Ok(()); - } - - ensure_identity(&state.pool).await?; - // Error events were supported by older clients. Drop any that remain in - // the local queue before selecting uploadable events. - sqlx::query("DELETE FROM telemetry_outbox WHERE event_type <> 'heartbeat'") - .execute(&state.pool) - .await?; - enqueue_heartbeat(state).await?; - cleanup_outbox(state).await?; - upload_next_batch(state, client).await?; - Ok(()) -} - -async fn is_enabled(state: &State) -> crate::Result { - let row = sqlx::query( - "SELECT telemetry, telemetry_consent_version FROM settings WHERE id = 0", - ) - .fetch_one(&state.pool) - .await?; - Ok(row.get::("telemetry") == 1 - && row.get::("telemetry_consent_version") > 0) -} - -async fn ensure_identity(pool: &sqlx::SqlitePool) -> crate::Result { - if let Some(row) = sqlx::query( - "SELECT installation_id FROM telemetry_identity WHERE id = 0", - ) - .fetch_optional(pool) - .await? - { - return Ok(row.get("installation_id")); - } - - let installation_id = Uuid::new_v4().to_string(); - sqlx::query( - "INSERT OR IGNORE INTO telemetry_identity (id, installation_id) VALUES (0, ?)", - ) - .bind(&installation_id) - .execute(pool) - .await?; - let row = sqlx::query( - "SELECT installation_id FROM telemetry_identity WHERE id = 0", - ) - .fetch_one(pool) - .await?; - Ok(row.get("installation_id")) -} - -async fn enqueue_heartbeat(state: &State) -> crate::Result<()> { - let day = Utc::now().format("%Y-%m-%d").to_string(); - let row = sqlx::query( - "SELECT last_heartbeat_day FROM telemetry_identity WHERE id = 0", - ) - .fetch_one(&state.pool) - .await?; - if row - .get::, _>("last_heartbeat_day") - .as_deref() - == Some(&day) - { - return Ok(()); - } - - let event_id = Uuid::new_v4().to_string(); - let occurred_at = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); - let payload = heartbeat_payload(&event_id, &occurred_at, &day); - insert_outbox_event( - state, - &event_id, - &format!("heartbeat:{day}"), - &payload, - ) - .await?; - sqlx::query( - "UPDATE telemetry_identity SET last_heartbeat_day = ? WHERE id = 0", - ) - .bind(day) - .execute(&state.pool) - .await?; - Ok(()) -} - -fn heartbeat_payload(event_id: &str, occurred_at: &str, day: &str) -> Value { - json!({ - "type": "heartbeat", - "event_id": event_id, - "occurred_at": occurred_at, - "day": day, - }) -} - -async fn insert_outbox_event( - state: &State, - event_id: &str, - dedupe_key: &str, - payload: &Value, -) -> crate::Result<()> { - let payload = serde_json::to_string(payload)?; - let now = Utc::now().timestamp(); - sqlx::query( - r#" - INSERT INTO telemetry_outbox ( - event_id, event_type, payload, created_at, next_attempt_at, - size_bytes, dedupe_key - ) VALUES (?, 'heartbeat', jsonb(?), ?, ?, ?, ?) - ON CONFLICT(dedupe_key) DO NOTHING - "#, - ) - .bind(event_id) - .bind(&payload) - .bind(now) - .bind(now) - .bind(payload.len() as i64) - .bind(dedupe_key) - .execute(&state.pool) - .await?; - cleanup_outbox(state).await -} - -async fn cleanup_outbox(state: &State) -> crate::Result<()> { - let oldest = Utc::now().timestamp() - MAX_EVENT_AGE_SECONDS; - sqlx::query("DELETE FROM telemetry_outbox WHERE created_at < ?") - .bind(oldest) - .execute(&state.pool) - .await?; - sqlx::query( - "DELETE FROM telemetry_outbox WHERE event_id IN (SELECT event_id FROM telemetry_outbox ORDER BY created_at DESC LIMIT -1 OFFSET ?)", - ) - .bind(MAX_OUTBOX_EVENTS) - .execute(&state.pool) - .await?; - sqlx::query( - r#" - DELETE FROM telemetry_outbox - WHERE event_id IN ( - SELECT event_id FROM ( - SELECT event_id, - SUM(size_bytes) OVER (ORDER BY created_at DESC, event_id DESC) AS running_bytes - FROM telemetry_outbox - ) - WHERE running_bytes > ? - ) - "#, - ) - .bind(MAX_OUTBOX_BYTES) - .execute(&state.pool) - .await?; - Ok(()) -} - -async fn upload_next_batch( - state: &State, - client: &reqwest::Client, -) -> crate::Result<()> { - let now = Utc::now().timestamp(); - let rows = sqlx::query( - "SELECT event_id, json(payload) AS payload FROM telemetry_outbox WHERE event_type = 'heartbeat' AND next_attempt_at <= ? ORDER BY created_at LIMIT ?", - ) - .bind(now) - .bind(MAX_BATCH_EVENTS) - .fetch_all(&state.pool) - .await?; - if rows.is_empty() { - return Ok(()); - } - - let mut events = Vec::new(); - let mut event_ids = Vec::new(); - let mut approximate_size = 0; - for row in rows { - let payload: String = row.get("payload"); - if approximate_size + payload.len() > MAX_BATCH_BYTES - && !events.is_empty() - { - break; - } - let event: Value = serde_json::from_str(&payload)?; - approximate_size += payload.len(); - events.push(event); - event_ids.push(row.get::("event_id")); - } - - let installation_id = ensure_identity(&state.pool).await?; - let batch_id = stable_batch_id(&event_ids); - let body = json!({ - "schema_version": 1, - "batch_id": batch_id, - "installation_id": installation_id, - "app": { - "version": env!("CARGO_PKG_VERSION"), - "environment": if cfg!(debug_assertions) { "development" } else { "production" }, - "platform": std::env::consts::OS, - "arch": std::env::consts::ARCH, - }, - "events": events, - }); - let endpoint = std::env::var("THESEUS_TELEMETRY_ENDPOINT") - .unwrap_or_else(|_| ENDPOINT.to_string()); - let response = client.post(endpoint).json(&body).send().await; - match response { - Ok(response) if response.status().is_success() => { - delete_events(state, &event_ids).await?; - } - Ok(response) - if response.status().is_client_error() - && response.status().as_u16() != 429 => - { - delete_events(state, &event_ids).await?; - } - _ => schedule_retry(state, &event_ids).await?, - } - Ok(()) -} - -async fn delete_events( - state: &State, - event_ids: &[String], -) -> crate::Result<()> { - for event_id in event_ids { - sqlx::query("DELETE FROM telemetry_outbox WHERE event_id = ?") - .bind(event_id) - .execute(&state.pool) - .await?; - } - Ok(()) -} - -async fn schedule_retry( - state: &State, - event_ids: &[String], -) -> crate::Result<()> { - for event_id in event_ids { - let row = sqlx::query( - "SELECT attempts FROM telemetry_outbox WHERE event_id = ?", - ) - .bind(event_id) - .fetch_optional(&state.pool) - .await?; - let Some(row) = row else { continue }; - let attempts = row.get::("attempts") + 1; - let delay = match attempts { - 1 => 60, - 2 => 5 * 60, - 3 => 30 * 60, - _ => 6 * 60 * 60, - }; - sqlx::query( - "UPDATE telemetry_outbox SET attempts = ?, next_attempt_at = ? WHERE event_id = ?", - ) - .bind(attempts) - .bind(Utc::now().timestamp() + delay) - .bind(event_id) - .execute(&state.pool) - .await?; - } - Ok(()) -} - -fn stable_batch_id(event_ids: &[String]) -> String { - let mut hasher = Sha256::new(); - for event_id in event_ids { - hasher.update(event_id.as_bytes()); - hasher.update([0]); - } - let digest = hex_digest(hasher.finalize().as_slice()); - format!( - "{}-{}-{}-{}-{}", - &digest[0..8], - &digest[8..12], - &digest[12..16], - &digest[16..20], - &digest[20..32] - ) -} - -fn hex_digest(bytes: &[u8]) -> String { - let mut output = String::with_capacity(bytes.len() * 2); - for byte in bytes { - let _ = write!(output, "{byte:02x}"); - } - output -} - -fn wake() { - if let Some(sender) = WAKE_TX.get() { - let _ = sender.try_send(()); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn batch_ids_are_stable() { - let ids = vec!["one".to_string(), "two".to_string()]; - assert_eq!(stable_batch_id(&ids), stable_batch_id(&ids)); - assert_ne!(stable_batch_id(&ids), stable_batch_id(&ids[..1])); - } - - #[test] - fn heartbeat_payload_matches_the_strict_worker_shape() { - let payload = heartbeat_payload( - "11111111-1111-4111-8111-111111111111", - "2026-08-17T00:00:00.000Z", - "2026-08-17", - ); - assert_eq!(payload.as_object().unwrap().len(), 4); - assert!(payload.get("download_stats").is_none()); - assert_eq!(payload["type"], "heartbeat"); - } -} diff --git a/packages/app-lib/src/util/download/h2_download.rs b/packages/app-lib/src/util/download/h2_download.rs index 98c0384..ac3fa06 100644 --- a/packages/app-lib/src/util/download/h2_download.rs +++ b/packages/app-lib/src/util/download/h2_download.rs @@ -7,8 +7,7 @@ use super::h2_pool::{H2ConnectFailureKind, SharedH2Connection}; use crate::util::fetch; use crate::util::fetch::{ - DownloadRequest, DownloadResult, DownloadRoute, DownloadRouteSource, - Integrity, + DownloadRequest, DownloadResult, DownloadRoute, Integrity, }; use futures::StreamExt; use http::header::{ACCEPT_ENCODING, RANGE, USER_AGENT}; @@ -395,16 +394,6 @@ pub(crate) fn request_headers( } } } - if route.source == DownloadRouteSource::Official - && fetch::is_official_modrinth_download_url(&request.url) - && let Some(download_meta) = &request.download_meta - { - if let Ok(value) = - HeaderValue::from_str(&download_meta.to_header_value()) - { - headers.insert("modrinth-download-meta", value); - } - } headers } diff --git a/packages/app-lib/src/util/fetch.rs b/packages/app-lib/src/util/fetch.rs index c02c297..b58abf1 100644 --- a/packages/app-lib/src/util/fetch.rs +++ b/packages/app-lib/src/util/fetch.rs @@ -45,8 +45,6 @@ fn is_safe_redirect_location(location: &str) -> bool { } use uuid::Uuid; -pub const DOWNLOAD_META_HEADER: &str = "modrinth-download-meta"; - const BMCLAPI_BASE_URL: &str = "https://bmclapi2.bangbang93.com"; const MCIM_BASE_URL: &str = "https://mod.mcimirror.top"; pub(crate) const TIANPAO_HOST: &str = "mod.tianpao.top"; @@ -253,7 +251,6 @@ pub struct DownloadRequest { pub url: String, pub resource: ResourceClass, pub integrity: Integrity, - pub download_meta: Option, pub header: Option<(String, String)>, pub candidate_urls: Vec, /// Whether range-segmented (multi-connection) downloading is allowed. @@ -283,7 +280,6 @@ impl DownloadRequest { url: url.into(), resource, integrity: Integrity::default(), - download_meta: None, header: None, candidate_urls: Vec::new(), allow_segmented_download: true, @@ -318,11 +314,6 @@ impl DownloadRequest { self } - pub fn with_download_meta(mut self, download_meta: DownloadMeta) -> Self { - self.download_meta = Some(download_meta); - self - } - pub fn with_header( mut self, name: impl Into, @@ -1077,19 +1068,6 @@ fn route_host(route: &DownloadRoute) -> Option { .and_then(|url| url.host_str().map(str::to_string)) } -pub(crate) fn is_official_modrinth_download_url(url: &str) -> bool { - Url::parse(url).is_ok_and(|url| { - matches!( - url.host_str(), - Some( - "api.modrinth.com" - | "cdn.modrinth.com" - | "cdn-alt.modrinth.com" - ) - ) - }) -} - fn is_official_version_manifest_url(url: &str) -> bool { Url::parse(url).is_ok_and(|url| { matches!( @@ -1300,30 +1278,6 @@ fn infer_resource_class(url: &str) -> ResourceClass { } } -#[derive(Debug, derive_more::Display, Clone, Copy, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -#[display(rename_all = "snake_case")] -pub enum DownloadReason { - Standalone, - Dependency, - Modpack, - Update, -} - -#[derive(Debug, Clone, Serialize)] -pub struct DownloadMeta { - pub reason: DownloadReason, - pub game_version: String, - pub loader: String, - pub dependent_on: Option, -} - -impl DownloadMeta { - pub fn to_header_value(&self) -> String { - serde_json::to_string(self).unwrap_or_default() - } -} - #[derive(Debug)] pub struct IoSemaphore(pub Semaphore); #[derive(Debug)] @@ -1956,7 +1910,6 @@ async fn fetch_hedged_metadata( pub async fn fetch( url: &str, sha1: Option<&str>, - download_meta: Option<&DownloadMeta>, uri_path: Option<&'static str>, semaphore: &FetchSemaphore, exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>, @@ -1967,7 +1920,6 @@ pub async fn fetch( sha1, None, None, - download_meta, None, uri_path, semaphore, @@ -1981,7 +1933,6 @@ pub async fn fetch( pub async fn fetch_official( url: &str, sha1: Option<&str>, - download_meta: Option<&DownloadMeta>, uri_path: Option<&'static str>, semaphore: &FetchSemaphore, exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>, @@ -1993,7 +1944,6 @@ pub async fn fetch_official( sha1, None, None, - download_meta, None, uri_path, semaphore, @@ -2033,7 +1983,6 @@ where json_body, None, None, - None, uri_path, semaphore, exec, @@ -2086,7 +2035,6 @@ where json_body, None, None, - None, uri_path, semaphore, exec, @@ -2110,7 +2058,6 @@ pub async fn fetch_advanced( sha1: Option<&str>, json_body: Option, header: Option<(&str, &str)>, - download_meta: Option<&DownloadMeta>, loading_bar: Option<(&LoadingBarId, f64)>, uri_path: Option<&'static str>, semaphore: &FetchSemaphore, @@ -2122,7 +2069,6 @@ pub async fn fetch_advanced( sha1, json_body, header, - download_meta, loading_bar, uri_path, semaphore, @@ -2141,7 +2087,6 @@ pub async fn fetch_advanced_with_client( sha1: Option<&str>, json_body: Option, header: Option<(&str, &str)>, - download_meta: Option<&DownloadMeta>, loading_bar: Option<(&LoadingBarId, f64)>, uri_path: Option<&'static str>, semaphore: &FetchSemaphore, @@ -2154,7 +2099,6 @@ pub async fn fetch_advanced_with_client( sha1, json_body, header, - download_meta, loading_bar, uri_path, semaphore, @@ -2176,7 +2120,6 @@ async fn fetch_advanced_with_client_and_progress( sha1: Option<&str>, json_body: Option, header: Option<(&str, &str)>, - download_meta: Option<&DownloadMeta>, loading_bar: Option<(&LoadingBarId, f64)>, uri_path: Option<&'static str>, semaphore: &FetchSemaphore, @@ -2224,7 +2167,6 @@ async fn fetch_advanced_with_client_and_progress( let mut attempt_history = VecDeque::new(); let hedge_is_safe = method == Method::GET && json_body.is_none() - && download_meta.is_none() && progress.is_none() && creds.is_none() && header.is_none_or(|(name, _)| !is_sensitive_header(name)) @@ -2273,15 +2215,6 @@ async fn fetch_advanced_with_client_and_progress( let route_source = route.source; let request_target = if is_mirror { "mirror" } else { "official" }; let has_next_route = route_index + 1 < request_routes.len(); - let download_meta_header = (!is_mirror - && is_official_modrinth_download_url(request_url)) - .then(|| { - download_meta.map(|m| { - (DOWNLOAD_META_HEADER.to_string(), m.to_header_value()) - }) - }) - .flatten(); - let max_attempts = if modrinth_request_kind == Some("CDN") { if is_mirror { 1 } else { MODRINTH_CDN_ATTEMPTS } } else { @@ -2309,7 +2242,6 @@ async fn fetch_advanced_with_client_and_progress( ); let protected_headers = creds.is_some() - || download_meta_header.is_some() || header.is_some_and(|header| is_sensitive_header(header.0)); let route_client = match (route.proxy, protected_headers) { (ProxyPolicy::System, false) @@ -2344,11 +2276,6 @@ async fn fetch_advanced_with_client_and_progress( req = req.header("Authorization", &creds.session); } - if let Some((name, value)) = &download_meta_header { - tracing::debug!("Sending download analytics: {value}"); - req = req.header(name.as_str(), value.as_str()); - } - let permit = semaphore.0.acquire().await?; let request_started = Instant::now(); let result = req.send().await; @@ -3418,7 +3345,6 @@ async fn send_path_request_with_clients( route: &DownloadRoute, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, range_start: Option, range_end: Option, system_client: &reqwest::Client, @@ -3468,14 +3394,6 @@ async fn send_path_request_with_clients( if allow_sensitive && let Some(credentials) = credentials { request = request.header("Authorization", &credentials.session); } - if !route.is_mirror - && same_as_original - && is_official_modrinth_download_url(original.as_str()) - && let Some(download_meta) = download_meta - { - request = request - .header(DOWNLOAD_META_HEADER, download_meta.to_header_value()); - } if let Some(range) = byte_range_header_value(range_start, range_end) { request = request .header(header::RANGE, range) @@ -3581,7 +3499,6 @@ async fn send_path_request( route: &DownloadRoute, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, range_start: Option, range_end: Option, ) -> crate::Result<(reqwest::Response, String)> { @@ -3589,7 +3506,6 @@ async fn send_path_request( route, custom_header, credentials, - download_meta, range_start, range_end, &NO_REDIRECT_REQWEST_CLIENT, @@ -4034,7 +3950,6 @@ async fn probe_route_throughput( total_size: u64, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, semaphore: &FetchSemaphore, system_client: &reqwest::Client, direct_client: &reqwest::Client, @@ -4054,7 +3969,6 @@ async fn probe_route_throughput( route, custom_header, credentials, - download_meta, Some(0), Some(probe_end), system_client, @@ -4134,7 +4048,6 @@ async fn probe_faster_route( total_size: u64, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, semaphore: &FetchSemaphore, system_client: &reqwest::Client, direct_client: &reqwest::Client, @@ -4162,7 +4075,6 @@ async fn probe_faster_route( total_size, custom_header, credentials, - download_meta, semaphore, system_client, direct_client, @@ -4339,7 +4251,6 @@ async fn ensure_task_routes_probed( size, request.header.as_ref(), None, - request.download_meta.as_ref(), semaphore, system_client, direct_client, @@ -4473,7 +4384,6 @@ async fn download_tail_candidate( requested_end: u64, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, part_path: &Path, candidate_index: usize, system_client: &reqwest::Client, @@ -4493,7 +4403,6 @@ async fn download_tail_candidate( route, custom_header, credentials, - download_meta, Some(requested_start), Some(requested_end), system_client, @@ -4588,7 +4497,6 @@ async fn race_tail_candidates( requested_end: u64, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, part_path: &Path, system_client: &reqwest::Client, direct_client: &reqwest::Client, @@ -4603,7 +4511,6 @@ async fn race_tail_candidates( requested_end, custom_header, credentials, - download_meta, part_path, 0, system_client, @@ -4619,7 +4526,6 @@ async fn race_tail_candidates( requested_end, custom_header, credentials, - download_meta, part_path, 1, system_client, @@ -4647,7 +4553,6 @@ async fn download_segment( total_size: u64, custom_header: Option<&(String, String)>, credentials: Option<&crate::state::ModrinthCredentials>, - download_meta: Option<&DownloadMeta>, part_path: &Path, output: &Arc, _permit: NativeConnectionPermit<'_>, @@ -4691,7 +4596,6 @@ async fn download_segment( route, custom_header, credentials, - download_meta, Some(requested_start), Some(requested_end), system_client, @@ -4819,7 +4723,6 @@ async fn download_segment( hedge_end, custom_header, credentials, - download_meta, part_path, system_client, direct_client, @@ -5085,7 +4988,6 @@ async fn try_segmented_download( size, request.header.as_ref(), credentials, - request.download_meta.as_ref(), part_path, &output, permit, @@ -5208,7 +5110,6 @@ async fn try_segmented_download( size, request.header.as_ref(), credentials, - request.download_meta.as_ref(), semaphore, system_client, direct_client, @@ -5305,7 +5206,6 @@ async fn try_segmented_download( size, request.header.as_ref(), credentials, - None, part_path, &output, permit, @@ -6216,7 +6116,6 @@ async fn download_to_path_inner( &attempt_route, request.header.as_ref(), credentials.as_ref(), - request.download_meta.as_ref(), (resume_offset > 0).then_some(resume_offset), None, ), @@ -6600,7 +6499,6 @@ async fn download_to_path_inner( total_size, request.header.as_ref(), credentials.as_ref(), - request.download_meta.as_ref(), semaphore, &NO_REDIRECT_REQWEST_CLIENT, &DIRECT_REQWEST_CLIENT, @@ -6975,28 +6873,6 @@ async fn download_to_path_inner( )) } -/// Posts a JSON to a URL -#[tracing::instrument(skip_all)] -pub async fn post_json( - url: &str, - json_body: serde_json::Value, - semaphore: &FetchSemaphore, - exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>, -) -> crate::Result<()> { - let _permit = semaphore.0.acquire().await?; - - let mut req = INSECURE_REQWEST_CLIENT.post(url).json(&json_body); - - if let Some(creds) = - crate::state::ModrinthCredentials::get_active(exec).await? - { - req = req.header("Authorization", &creds.session); - } - - req.send().await?.error_for_status()?; - Ok(()) -} - pub async fn read_json( path: &Path, semaphore: &IoSemaphore, @@ -7526,22 +7402,6 @@ mod tests { } } - #[test] - fn modrinth_download_url_recognition_includes_cdn_alt() { - assert!(is_official_modrinth_download_url( - "https://cdn-alt.modrinth.com/data/project/version/file.jar" - )); - assert!(is_official_modrinth_download_url( - "https://cdn.modrinth.com/data/project/version/file.jar" - )); - assert!(is_official_modrinth_download_url( - "https://api.modrinth.com/v2/project/abc" - )); - assert!(!is_official_modrinth_download_url( - "https://example.com/file.jar" - )); - } - #[test] fn cache_busted_urls_preserve_existing_query() { assert_eq!( @@ -8678,7 +8538,6 @@ mod tests { data.len() as u64, None, None, - None, &semaphore, &client, &client, @@ -8707,7 +8566,6 @@ mod tests { data.len() as u64, None, None, - None, &semaphore, &client, &client, @@ -9044,7 +8902,6 @@ mod tests { data.len() as u64, None, None, - None, &part_path, &output, permit, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9d32ff..04624b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,11 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -patchedDependencies: - readable-stream@2.3.8: - hash: 3045f7adf989b4e668a4a13819b7285b0de186b79bbf22408acaf2a41c6eaa86 - path: patches/readable-stream@2.3.8.patch - importers: .: @@ -18,7 +13,7 @@ importers: version: 1.1.0 '@crowdin/crowdin-api-client': specifier: ^1.55.2 - version: 1.55.2 + version: 1.55.2(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) '@formatjs/icu-messageformat-parser': specifier: ^2.11.4 version: 2.11.4 @@ -182,7 +177,7 @@ importers: devDependencies: '@eslint/compat': specifier: ^1.1.1 - version: 1.4.1(eslint@9.39.2(jiti@1.21.7)) + version: 1.4.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) '@formatjs/cli': specifier: ^6.2.12 version: 6.12.2(@vue/compiler-core@3.5.27)(vue@3.5.27(typescript@5.9.3)) @@ -191,7 +186,7 @@ importers: version: link:../../packages/tooling-config '@nuxt/eslint-config': specifier: ^0.5.6 - version: 0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + version: 0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) '@vitejs/plugin-vue': specifier: ^6.0.3 version: 6.0.4(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) @@ -200,10 +195,10 @@ importers: version: 10.4.24(postcss@8.5.6) eslint: specifier: ^9.9.1 - version: 9.39.2(jiti@1.21.7) + version: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) eslint-plugin-turbo: specifier: ^2.5.4 - version: 2.8.2(eslint@9.39.2(jiti@1.21.7))(turbo@2.8.2) + version: 2.8.2(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(turbo@2.8.2) postcss: specifier: ^8.4.39 version: 8.5.6 @@ -224,7 +219,7 @@ importers: version: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vite-plugin-vue-devtools: specifier: ^8.2.1 - version: 8.2.1(@nuxt/kit@3.21.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + version: 8.2.1(@nuxt/kit@3.21.0(magicast@0.5.1))(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) vue-component-type-helpers: specifier: ^3.1.8 version: 3.2.4 @@ -232,116 +227,6 @@ importers: specifier: ^2.1.6 version: 2.2.12(typescript@5.9.3) - apps/telemetry-dashboard: - dependencies: - '@aws-sdk/client-s3': - specifier: ^3.1105.0 - version: 3.1105.0 - '@unovis/vue': - specifier: ^1.6.1 - version: 1.6.7(@unovis/ts@1.6.7)(vue@3.5.27(typescript@5.9.3)) - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - jose: - specifier: ^6.1.0 - version: 6.2.8 - lucide-vue-next: - specifier: ^0.468.0 - version: 0.468.0(vue@3.5.27(typescript@5.9.3)) - nuxt: - specifier: '=3.20.2' - version: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) - reka-ui: - specifier: ^2.6.0 - version: 2.10.1(vue@3.5.27(typescript@5.9.3)) - tailwind-merge: - specifier: ^2.6.0 - version: 2.6.1 - vue: - specifier: ^3.5.13 - version: 3.5.27(typescript@5.9.3) - vue-router: - specifier: '*' - version: 4.6.4(vue@3.5.27(typescript@5.9.3)) - zod: - specifier: ^3.25.76 - version: 3.25.76 - devDependencies: - '@cloudflare/vitest-pool-workers': - specifier: ^0.8.69 - version: 0.8.71(@cloudflare/workers-types@5.20260804.1)(@vitest/runner@3.2.7)(@vitest/snapshot@3.2.7)(vitest@3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)) - '@cloudflare/workers-types': - specifier: ^5.20260801.1 - version: 5.20260804.1 - '@modrinth/tooling-config': - specifier: workspace:* - version: link:../../packages/tooling-config - '@types/node': - specifier: ^24 - version: 24.12.2 - '@vitejs/plugin-vue': - specifier: ^5.2.4 - version: 5.2.4(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) - '@vue/test-utils': - specifier: ^2.4.6 - version: 2.4.11(@vue/compiler-dom@3.5.27)(@vue/server-renderer@3.5.27(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3)) - autoprefixer: - specifier: ^10.4.19 - version: 10.4.24(postcss@8.5.8) - happy-dom: - specifier: ^18.0.1 - version: 18.0.1 - postcss: - specifier: ^8.4.39 - version: 8.5.8 - prettier-plugin-tailwindcss: - specifier: ^0.6.5 - version: 0.6.14(prettier@3.8.1) - tailwindcss: - specifier: ^3.4.4 - version: 3.4.19(yaml@2.8.2) - typescript: - specifier: ^5.9.2 - version: 5.9.3 - vitest: - specifier: ^3.2.4 - version: 3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - wrangler: - specifier: ^4.28.1 - version: 4.119.0(@cloudflare/workers-types@5.20260804.1) - - apps/telemetry-worker: - dependencies: - hono: - specifier: ^4.9.2 - version: 4.13.1 - zod: - specifier: ^3.25.76 - version: 3.25.76 - devDependencies: - '@cloudflare/vitest-pool-workers': - specifier: ^0.8.69 - version: 0.8.71(@cloudflare/workers-types@5.20260804.1)(@vitest/runner@3.2.7)(@vitest/snapshot@3.2.7)(vitest@3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)) - '@cloudflare/workers-types': - specifier: ^5.20260801.1 - version: 5.20260804.1 - '@types/node': - specifier: ^24 - version: 24.12.2 - typescript: - specifier: ^5.9.2 - version: 5.9.3 - vitest: - specifier: ^3.2.4 - version: 3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - wrangler: - specifier: ^4.28.1 - version: 4.119.0(@cloudflare/workers-types@5.20260804.1) - apps/website: dependencies: '@modrinth/assets': @@ -350,9 +235,6 @@ importers: '@modrinth/ui': specifier: workspace:* version: link:../../packages/ui - howxm-js: - specifier: 0.0.10 - version: 0.0.10(react@19.2.4) intl-messageformat: specifier: ^10.7.7 version: 10.7.18 @@ -377,7 +259,7 @@ importers: version: 10.4.24(postcss@8.5.8) nuxt: specifier: '=3.20.2' - version: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) + version: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) postcss: specifier: ^8.4.39 version: 8.5.8 @@ -467,43 +349,43 @@ importers: devDependencies: '@eslint/compat': specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.2(jiti@2.6.1)) + version: 1.4.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) '@eslint/js': specifier: ^9.32.0 version: 9.39.2 '@nuxt/eslint-config': specifier: ^0.5.7 - version: 0.5.7(@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) + version: 0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) '@vue/tsconfig': specifier: ^0.7.0 version: 0.7.0(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)) eslint: specifier: ^9.32.0 - version: 9.39.2(jiti@2.6.1) + version: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) eslint-plugin-prettier: specifier: ^5.5.3 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(prettier@3.8.1) eslint-plugin-simple-import-sort: specifier: ^12.1.1 - version: 12.1.1(eslint@9.39.2(jiti@2.6.1)) + version: 12.1.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) eslint-plugin-turbo: specifier: ^2.5.4 - version: 2.8.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.2) + version: 2.8.2(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(turbo@2.8.2) eslint-plugin-vue: specifier: ^10.4.0 - version: 10.7.0(@stylistic/eslint-plugin@2.13.0(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))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) + version: 10.7.0(@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)) globals: specifier: ^16.3.0 version: 16.5.0 typescript-eslint: specifier: ^8.38.0 - version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) vue-eslint-parser: specifier: ^10.1.3 - version: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + version: 10.2.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) packages/ui: dependencies: @@ -747,78 +629,6 @@ packages: '@alvarosabu/utils@3.2.0': resolution: {integrity: sha512-aoGWRfaQjOo9TUwrBA6W0zwTHktgrXy69GIFNILT4gHsqscw6+X8P6uoSlZVQFr887SPm8x3aDin5EBVq8y4pw==} - '@aws-sdk/checksums@3.1000.26': - resolution: {integrity: sha512-CGznePoL+1oWCSzqmkvlYMpWQEZohPR3LntjKXXfVH+oh6Kd8d+yHLkjpiAGwPIHAxFe4OAq3aKfRnv/wqWIyA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/client-s3@3.1105.0': - resolution: {integrity: sha512-eiR289CNgH2atIh2zOSDSpXOmDVGCxFEk0S8jMHo599oTCjcnjmlNOVsFCWXx5jMPP83+c47Wl/1R7xgUVBzZw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/core@3.977.6': - resolution: {integrity: sha512-QiaJV4/zDrB4ZY2mfeSXSzSTc36W16sZXcGz+SPFk0CJ26gziO0cS+4LjJUMAbdeeBOvS0k0Aq1cZpfGdUXxSw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-env@3.972.67': - resolution: {integrity: sha512-rcIpk5kxUqDaaNa6Xk23pQ6ViY7jlqzmfFWCahQcBT97ddXaXYYwzCen9Tz1Jvo6aJft6wDl5bN44/Jw5B4oLA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-http@3.972.69': - resolution: {integrity: sha512-nggwJtZ4eeNsUw5IeWBMXsi1ryct5idi0K+/SCRF3kybLubOMaNTb3XCihXpWMiVpyzyPeIrl0zTkzhBH9porA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-ini@3.973.12': - resolution: {integrity: sha512-pNEf/OeyN5X3VmLKlgSO6TqaWmW10CvI3TfwL1XhsuhYjSLT2VDaxFnCPHnOeQXSaFisMX4jNhpETriqN8DOmg==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-login@3.972.74': - resolution: {integrity: sha512-0AQfDcf99TNmqVKv0owHrw/TQs6i4ZE5t9qmz6NvO53bE/sA/tpXhXL9AAcEP1qHc6Zzjd1UMb69+/9zdhvY3g==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-node@3.972.78': - resolution: {integrity: sha512-OgPAnfvbGAMWac6yvxJ1ihslrvDpPVwR68D2csospdNCCyPvHk9JLzYKwz48SNiS1T2znDwHauywRKRFfpyYng==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-process@3.972.67': - resolution: {integrity: sha512-IlUEejorGTWKb4/Dm7K5Yw4QxUmXLThLhrvBmzVBqZFTbW72cv9LTcITmo1dsnYriALE4h68mOq4LB99x6sQ7Q==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-sso@3.973.11': - resolution: {integrity: sha512-gAQBkBZxUB84d71+pPcI9L+jh2ujhuAVxc/4FgGiWFDjkPBlMKxzd5XDtkSXTFX8Ro7ansnT88+XadasxMeCRw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.972.73': - resolution: {integrity: sha512-SnlEmQa6SjOgs6iOPLUQl1Eyq4AKiAdPQlkOhFhqNfDtDCwibMGvL6QlkSmf3o6vAUSImzdPCxowT5dfQUZP1A==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/middleware-sdk-s3@3.972.72': - resolution: {integrity: sha512-lSAoVPvQxX1d8TOM6waKDBQrvvZcm4w6pCldFAsRUffEaXq6lYY0pPyew3KlLu6Xqb74DXI42hGvSsbGBLljlw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/nested-clients@3.997.41': - resolution: {integrity: sha512-RDHqPGQWlF6tatA/Tp3rg6oIwtgN9IVderxE+9av2Y93Dfyu+mO1hZ5Bu2jpfZg2rwdNbsssnwM+sLafIczMlQ==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/signature-v4-multi-region@3.996.43': - resolution: {integrity: sha512-lKekx8bLBXSv4O+cslk9Zfnw2XKSkWBs3uWL5QGhH2ZAQfNS7FE0vcSSN2vD/AhxX54ZTywWxR4STThoeOXlBA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/token-providers@3.1103.0': - resolution: {integrity: sha512-N4wy26MNn31ItGVHYHPrEuCIFY4MBBjC+C5v1lJKqIUSA7OZBdhleCY53zCCrXn27hsk7YNOaTuhQu807S4AfQ==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/types@3.974.2': - resolution: {integrity: sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/xml-builder@3.972.37': - resolution: {integrity: sha512-zKq4HQum8JwDyEuyfuI4bbiAcU0KxP6qy+9PR/IsR92IyE/DaBAikzAS50tjxip4bqIIANpCcG+Yyj6CVhXupg==} - engines: {node: '>=20.0.0'} - - '@aws/lambda-invoke-store@0.3.0': - resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} - engines: {node: '>=18.0.0'} - '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -1004,10 +814,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.29.7': - resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} - engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -1059,106 +865,10 @@ packages: '@clack/prompts@1.1.0': resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==} - '@cloudflare/kv-asset-handler@0.4.0': - resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} - engines: {node: '>=18.0.0'} - '@cloudflare/kv-asset-handler@0.4.2': resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} engines: {node: '>=18.0.0'} - '@cloudflare/kv-asset-handler@0.5.0': - resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} - engines: {node: '>=22.0.0'} - - '@cloudflare/unenv-preset@2.16.1': - resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} - peerDependencies: - unenv: 2.0.0-rc.24 - workerd: '>1.20260305.0 <2.0.0-0' - peerDependenciesMeta: - workerd: - optional: true - - '@cloudflare/unenv-preset@2.7.3': - resolution: {integrity: sha512-tsQQagBKjvpd9baa6nWVIv399ejiqcrUBBW6SZx6Z22+ymm+Odv5+cFimyuCsD/fC1fQTwfRmwXBNpzvHSeGCw==} - peerDependencies: - unenv: 2.0.0-rc.21 - workerd: ^1.20250828.1 - peerDependenciesMeta: - workerd: - optional: true - - '@cloudflare/vitest-pool-workers@0.8.71': - resolution: {integrity: sha512-keu2HCLQfRNwbmLBCDXJgCFpANTaYnQpE01fBOo4CNwiWHUT7SZGN7w64RKiSWRHyYppStXBuE5Ng7F42+flpg==} - peerDependencies: - '@vitest/runner': 2.0.x - 3.2.x - '@vitest/snapshot': 2.0.x - 3.2.x - vitest: 2.0.x - 3.2.x - - '@cloudflare/workerd-darwin-64@1.20250906.0': - resolution: {integrity: sha512-E+X/YYH9BmX0ew2j/mAWFif2z05NMNuhCTlNYEGLkqMe99K15UewBqajL9pMcMUKxylnlrEoK3VNxl33DkbnPA==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - - '@cloudflare/workerd-darwin-64@1.20260801.1': - resolution: {integrity: sha512-wuJWbXpKvncJi1P0GKS+iYpN5tHdb7JPJJ/+6ZQe8zzovHHVMkLJPNBsgWpqeUhpM3g9qTwEKd2rglNKejuh5A==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - - '@cloudflare/workerd-darwin-arm64@1.20250906.0': - resolution: {integrity: sha512-X5apsZ1SFW4FYTM19ISHf8005FJMPfrcf4U5rO0tdj+TeJgQgXuZ57IG0WeW7SpLVeBo8hM6WC8CovZh41AfnA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - - '@cloudflare/workerd-darwin-arm64@1.20260801.1': - resolution: {integrity: sha512-kwoZiTpnhNrF3+APx84Q/oAqvJ3sU9yefGagwm/ASaH/2W19x0vghkW/r4qCoHCK0WW7EPugZ+aXjgPMRtlq1Q==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - - '@cloudflare/workerd-linux-64@1.20250906.0': - resolution: {integrity: sha512-rlKzWgsLnlQ5Nt9W69YBJKcmTmZbOGu0edUsenXPmc6wzULUxoQpi7ZE9k3TfTonJx4WoQsQlzCUamRYFsX+0Q==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - - '@cloudflare/workerd-linux-64@1.20260801.1': - resolution: {integrity: sha512-r0vAxCZH+Jih9Unm1yoyiByPNWNgawcKciOHDm5Q37ZVGOkKLsT9AtLe3yLSaul76WrKqtf+JP2n0WW32VBLJg==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - - '@cloudflare/workerd-linux-arm64@1.20250906.0': - resolution: {integrity: sha512-DdedhiQ+SeLzpg7BpcLrIPEZ33QKioJQ1wvL4X7nuLzEB9rWzS37NNNahQzc1+44rhG4fyiHbXBPOeox4B9XVA==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - - '@cloudflare/workerd-linux-arm64@1.20260801.1': - resolution: {integrity: sha512-zWgpdZtSozvIgzQNmQiDSF8yEOQJUkRAWNsDXXzAAoy+fCn8YUoSibj3mpFSbZRvbUldeBEaW6SCdC2VEMkhNQ==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - - '@cloudflare/workerd-windows-64@1.20250906.0': - resolution: {integrity: sha512-Q8Qjfs8jGVILnZL6vUpQ90q/8MTCYaGR3d1LGxZMBqte8Vr7xF3KFHPEy7tFs0j0mMjnqCYzlofmPNY+9ZaDRg==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - - '@cloudflare/workerd-windows-64@1.20260801.1': - resolution: {integrity: sha512-2oQz+Ksu4ji6e/+ZoYX+tWQEcxAii2p7l+iR8kx48W1llMalaufAsmVxTlk+3/vrM7D3/2c0iK448e0UQTcIMg==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - - '@cloudflare/workers-types@5.20260804.1': - resolution: {integrity: sha512-B1dwxpN6e5RZXZkE5zpZj+ooNeNZ1mwavLIyHDYe10ojhlGTwDfe8sAl7R1mMXc1cyIsbr+jKVdvmMEyVcdTdg==} - '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} @@ -1193,10 +903,6 @@ packages: resolution: {integrity: sha512-kEMiz25j9tSfhsyj8dZWdhKPdtTeVu9lWZFBIc+adHXZ8vs6zd4/6xaiYr3PamYhV3rIOBEv8ElyzpUSSO5LGg==} engines: {node: '>=12.9.0'} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - '@dxup/nuxt@0.2.2': resolution: {integrity: sha512-RNpJjDZs9+JcT9N87AnOuHsNM75DEd58itADNd/s1LIF6BZbTLZV0xxilJZb55lntn4TYvscTaXLCBX2fq9CXg==} @@ -1209,42 +915,9 @@ packages: '@emnapi/runtime@1.11.3': resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} - '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@emotion/babel-plugin@11.13.5': - resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} - - '@emotion/cache@11.14.0': - resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} - - '@emotion/css@11.13.5': - resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} - - '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - - '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - - '@emotion/serialize@1.3.3': - resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - - '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - - '@emotion/unitless@0.10.0': - resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - - '@emotion/utils@1.4.2': - resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} - - '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@es-joy/jsdoccomment@0.50.2': resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} engines: {node: '>=18'} @@ -1255,12 +928,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.4': - resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} @@ -1273,24 +940,12 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.28.1': - resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.4': - resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.2': resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} @@ -1303,24 +958,12 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.28.1': - resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.4': - resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.2': resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} @@ -1333,24 +976,12 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.28.1': - resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.4': - resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.2': resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} @@ -1363,24 +994,12 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.28.1': - resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.4': - resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.2': resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} @@ -1393,24 +1012,12 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.28.1': - resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.4': - resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.2': resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} @@ -1423,24 +1030,12 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.28.1': - resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.4': - resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.2': resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} @@ -1453,24 +1048,12 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.28.1': - resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.4': - resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} @@ -1483,24 +1066,12 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': - resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.4': - resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.2': resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} @@ -1513,24 +1084,12 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.28.1': - resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.4': - resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.2': resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} @@ -1543,24 +1102,12 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.28.1': - resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.4': - resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.2': resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} @@ -1573,24 +1120,12 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.28.1': - resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.4': - resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.2': resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} @@ -1603,24 +1138,12 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.28.1': - resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.4': - resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.2': resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} @@ -1633,24 +1156,12 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.28.1': - resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.4': - resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.2': resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} @@ -1663,24 +1174,12 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.28.1': - resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.4': - resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.2': resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} @@ -1693,24 +1192,12 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.28.1': - resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.4': - resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.2': resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} @@ -1723,24 +1210,12 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.28.1': - resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.4': - resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.2': resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} @@ -1753,18 +1228,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.28.1': - resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.4': - resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.2': resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} @@ -1777,24 +1240,12 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.28.1': - resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.4': - resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} @@ -1807,18 +1258,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': - resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.4': - resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.2': resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} @@ -1831,24 +1270,12 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.28.1': - resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.4': - resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} @@ -1861,12 +1288,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': - resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openharmony-arm64@0.27.2': resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} @@ -1879,24 +1300,12 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.28.1': - resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.4': - resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.2': resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} @@ -1909,24 +1318,12 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.28.1': - resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.4': - resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.2': resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} @@ -1939,24 +1336,12 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.28.1': - resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.4': - resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.2': resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} @@ -1969,24 +1354,12 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.28.1': - resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.4': - resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.2': resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} @@ -1999,12 +1372,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.28.1': - resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} - 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} @@ -2055,24 +1422,12 @@ packages: '@floating-ui/core@1.7.4': resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} - '@floating-ui/core@1.8.0': - resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} - '@floating-ui/dom@1.1.1': resolution: {integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==} - '@floating-ui/dom@1.8.0': - resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} - '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@floating-ui/utils@0.2.12': - resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - - '@floating-ui/vue@1.1.11': - resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} - '@formatjs/cli@6.12.2': resolution: {integrity: sha512-y215aarLZXei3u1WDRAiet/VajgvUXzvz4ifPENDSPXfIog0aBJKtFvIU7EWbcFWy7rstbn5GcwwQW4F1G3TJg==} engines: {node: '>= 16'} @@ -2161,291 +1516,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@img/colour@1.1.0': - resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} - engines: {node: '>=18'} - - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-arm64@0.35.2': - resolution: {integrity: sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==} - engines: {node: '>=20.9.0'} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-darwin-x64@0.35.2': - resolution: {integrity: sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==} - engines: {node: '>=20.9.0'} - cpu: [x64] - os: [darwin] - - '@img/sharp-freebsd-wasm32@0.35.2': - resolution: {integrity: sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==} - engines: {node: '>=20.9.0'} - os: [freebsd] - - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.3.1': - resolution: {integrity: sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.3.1': - resolution: {integrity: sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-arm64@1.3.1': - resolution: {integrity: sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-arm@1.3.1': - resolution: {integrity: sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-ppc64@1.3.1': - resolution: {integrity: sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-riscv64@1.3.1': - resolution: {integrity: sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-s390x@1.3.1': - resolution: {integrity: sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-x64@1.3.1': - resolution: {integrity: sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-libvips-linuxmusl-arm64@1.3.1': - resolution: {integrity: sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-libvips-linuxmusl-x64@1.3.1': - resolution: {integrity: sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-arm64@0.35.2': - resolution: {integrity: sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==} - engines: {node: '>=20.9.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-arm@0.35.2': - resolution: {integrity: sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==} - engines: {node: '>=20.9.0'} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-ppc64@0.35.2': - resolution: {integrity: sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==} - engines: {node: '>=20.9.0'} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-riscv64@0.35.2': - resolution: {integrity: sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==} - engines: {node: '>=20.9.0'} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-s390x@0.35.2': - resolution: {integrity: sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==} - engines: {node: '>=20.9.0'} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-x64@0.35.2': - resolution: {integrity: sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==} - engines: {node: '>=20.9.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-arm64@0.35.2': - resolution: {integrity: sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==} - engines: {node: '>=20.9.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-x64@0.35.2': - resolution: {integrity: sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==} - engines: {node: '>=20.9.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - - '@img/sharp-wasm32@0.35.2': - resolution: {integrity: sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==} - engines: {node: '>=20.9.0'} - - '@img/sharp-webcontainers-wasm32@0.35.2': - resolution: {integrity: sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==} - engines: {node: '>=20.9.0'} - cpu: [wasm32] - - '@img/sharp-win32-arm64@0.35.2': - resolution: {integrity: sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==} - engines: {node: '>=20.9.0'} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-ia32@0.35.2': - resolution: {integrity: sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==} - engines: {node: ^20.9.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@img/sharp-win32-x64@0.35.2': - resolution: {integrity: sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==} - engines: {node: '>=20.9.0'} - cpu: [x64] - os: [win32] - - '@internationalized/date@3.12.3': - resolution: {integrity: sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q==} - - '@internationalized/number@3.6.7': - resolution: {integrity: sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==} - '@intlify/core-base@10.0.8': resolution: {integrity: sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ==} engines: {node: '>= 16'} @@ -2496,12 +1566,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@juggle/resize-observer@3.4.0': - resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} - '@kwsites/file-exists@1.1.1': resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} @@ -2532,38 +1596,11 @@ packages: '@lobehub/icons-static-svg@1.94.0': resolution: {integrity: sha512-Inx1TYkjLH6YeHOIHeVW9+OM/xxRnk8TmcQVKquFUDBmE3X9sUuRGt7kALrrDBNNAbrWz7Qq6fAiFj9E9Mmw9Q==} - '@mapbox/geojson-rewind@0.5.2': - resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} - hasBin: true - - '@mapbox/jsonlint-lines-primitives@2.0.3': - resolution: {integrity: sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==} - engines: {node: '>= 22'} - - '@mapbox/mapbox-gl-supported@2.0.1': - resolution: {integrity: sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==} - '@mapbox/node-pre-gyp@2.0.3': resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} engines: {node: '>=18'} hasBin: true - '@mapbox/point-geometry@0.1.0': - resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} - - '@mapbox/tiny-sdf@2.2.0': - resolution: {integrity: sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==} - - '@mapbox/unitbezier@0.0.1': - resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} - - '@mapbox/vector-tile@1.3.1': - resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} - - '@mapbox/whoots-js@3.1.0': - resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} - engines: {node: '>=6.0.0'} - '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} @@ -2660,9 +1697,6 @@ packages: rolldown: optional: true - '@one-ini/wasm@0.1.1': - resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} - '@oxc-minify/binding-android-arm64@0.102.0': resolution: {integrity: sha512-pknM+ttJTwRr7ezn1v5K+o2P4RRjLAzKI10bjVDPybwWQ544AZW6jxm7/YDgF2yUbWEV9o7cAQPkIUOmCiW8vg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3395,30 +2429,6 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} - '@smithy/core@3.31.1': - resolution: {integrity: sha512-CyogUINxvi7C7LDsh8Syo6hVJOT9ckz4rG8dRZfTJ8r91HkMY59PnNooaj7WcHyxEkxPfBAmbgztZU+xTo76lg==} - engines: {node: '>=18.0.0'} - - '@smithy/credential-provider-imds@4.4.16': - resolution: {integrity: sha512-QfuLWAkLzptffFW980AFeHZFdqds2B64rpEd3uJ6lgs3xVn9QegGMUgUcj+4d7dRrAsya3r58ZKpku97WcFb4w==} - engines: {node: '>=18.0.0'} - - '@smithy/fetch-http-handler@5.6.13': - resolution: {integrity: sha512-4fW86pEUOMbrD5nkbyl/tTvPHHWJFbuB2odl6ps9lWfHoXf9HWh3Q/Smh59qH1g7+c/BSZghX6bbUk4gsiMs8A==} - engines: {node: '>=18.0.0'} - - '@smithy/node-http-handler@4.9.13': - resolution: {integrity: sha512-Nmd/Nl35zfYrd+a6OO2cDJb3GPh9bgTjIUhcM+JFfjpp8/osCgboDV5nCT1I01Pv6R13eSKDKLSoVa5ZB6Zsfw==} - engines: {node: '>=18.0.0'} - - '@smithy/signature-v4@5.6.12': - resolution: {integrity: sha512-I6KLtq3H0qqSuV9vLglfi8puHqzygzWHOnI4z/Rdoo+q50vvo18vBRdPAvvEtcaKROz7Zn6qnPa14kRfPH6PcQ==} - engines: {node: '>=18.0.0'} - - '@smithy/types@4.16.1': - resolution: {integrity: sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==} - engines: {node: '>=18.0.0'} - '@speed-highlight/core@1.2.14': resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} @@ -3457,9 +2467,6 @@ packages: peerDependencies: '@svgdotjs/svg.js': ^3.2.4 - '@swc/helpers@0.5.23': - resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} - '@tailwindcss/container-queries@0.1.1': resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} peerDependencies: @@ -3566,9 +2573,6 @@ packages: '@tanstack/query-core@5.90.7': resolution: {integrity: sha512-6PN65csiuTNfBMXqQUxQhCNdtm1rV+9kC9YwWAIKcaxAauq3Wu7p18j3gQY3YIBJU70jT/wzCCZ2uqto/vQgiQ==} - '@tanstack/virtual-core@3.17.7': - resolution: {integrity: sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==} - '@tanstack/vue-query@5.90.7': resolution: {integrity: sha512-2h0esebc2qVRVDge3gFArhss5+qn/Wb4abXuaEliSy+/xPWQMrEX7Ny0UKkCy1HcMZZjvfTtNRUfpYrx+vpipw==} peerDependencies: @@ -3578,11 +2582,6 @@ packages: '@vue/composition-api': optional: true - '@tanstack/vue-virtual@3.13.35': - resolution: {integrity: sha512-lOfSPvgPdlaH6Qy+CyIc3XpycitaSQ9GECndGpTuDiu+uDA1am+90yWXwzDSd/20ZM196ggWJLS+Qb6WjVd/OA==} - peerDependencies: - vue: ^2.7.0 || ^3.0.0 - '@taplo/core@0.2.0': resolution: {integrity: sha512-r8bl54Zj1In3QLkiW/ex694bVzpPJ9EhwqT9xkcUVODnVUGirdB1JTsmiIv0o1uwqZiwhi8xNnTOQBRQCpizrQ==} @@ -3719,120 +2718,6 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/d3-array@3.2.2': - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - - '@types/d3-axis@3.0.6': - resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} - - '@types/d3-brush@3.0.6': - resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} - - '@types/d3-chord@3.0.6': - resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} - - '@types/d3-collection@1.0.13': - resolution: {integrity: sha512-v0Rgw3IZebRyamcwVmtTDCZ8OmQcj4siaYjNc7wGMZT7PmdSHawGsCOQMxyLvZ7lWjfohYLK0oXtilMOMgfY8A==} - - '@types/d3-color@3.1.3': - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - - '@types/d3-contour@3.0.6': - resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} - - '@types/d3-delaunay@6.0.4': - resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} - - '@types/d3-dispatch@3.0.7': - resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} - - '@types/d3-drag@3.0.7': - resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} - - '@types/d3-dsv@3.0.7': - resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} - - '@types/d3-ease@3.0.2': - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - - '@types/d3-fetch@3.0.7': - resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} - - '@types/d3-force@3.0.10': - resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} - - '@types/d3-format@3.0.4': - resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} - - '@types/d3-geo@3.1.1': - resolution: {integrity: sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w==} - - '@types/d3-hierarchy@3.1.7': - resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} - - '@types/d3-interpolate@3.0.4': - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - - '@types/d3-path@1.0.11': - resolution: {integrity: sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==} - - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - - '@types/d3-polygon@3.0.2': - resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} - - '@types/d3-quadtree@3.0.6': - resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} - - '@types/d3-random@3.0.4': - resolution: {integrity: sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==} - - '@types/d3-sankey@0.12.5': - resolution: {integrity: sha512-/3RZSew0cLAtzGQ+C89hq/Rp3H20QJuVRSqFy6RKLe7E0B8kd2iOS1oBsodrgds4PcNVpqWhdUEng/SHvBcJ6Q==} - - '@types/d3-scale-chromatic@3.1.0': - resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} - - '@types/d3-scale@4.0.9': - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - - '@types/d3-selection@3.0.11': - resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} - - '@types/d3-shape@1.3.12': - resolution: {integrity: sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==} - - '@types/d3-shape@3.1.8': - resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} - - '@types/d3-time-format@4.0.3': - resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} - - '@types/d3-time@3.0.4': - resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} - - '@types/d3-timer@3.0.2': - resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - - '@types/d3-transition@3.0.9': - resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} - - '@types/d3-zoom@3.0.8': - resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} - - '@types/d3@7.4.3': - resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} - - '@types/dagre@0.7.54': - resolution: {integrity: sha512-QjcRY+adGbYvBFS7cwv5txhVIwX1XXIUswWl+kSQTbI6NjgZydrZkEKX/etzVd7i+bCsCb40Z/xlBY5eoFuvWQ==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/dompurify@3.2.0': resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==} deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed. @@ -3843,33 +2728,18 @@ 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==} - '@types/leaflet@1.7.6': - resolution: {integrity: sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA==} - '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - '@types/mapbox__point-geometry@0.1.4': - resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==} - - '@types/mapbox__vector-tile@1.3.4': - resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==} - '@types/markdown-it@14.1.2': resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} '@types/mdurl@2.0.0': resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/node@20.19.43': - resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} - '@types/node@24.12.2': resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} @@ -3879,49 +2749,19 @@ packages: '@types/offscreencanvas@2019.7.3': resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/parse-path@7.1.0': resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==} deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed. - '@types/pbf@3.0.5': - resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} - '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} '@types/stats.js@0.17.4': resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} - '@types/supercluster@5.0.3': - resolution: {integrity: sha512-XMSqQEr7YDuNtFwSgaHHOjsbi0ZGL62V9Js4CW45RBuRYlNWSW/KDqN+RFFE7HdHcGhJPtN0klKvw06r9Kg7rg==} - - '@types/three@0.135.0': - resolution: {integrity: sha512-l7WLhIHjhHMtlpyTSltPPAKLpiMwgMD1hXHj59AVUpYRoZP7Fd9NNOSRSvZBCPLpTHPYojgQvSJCoza9zoL7bg==} - '@types/three@0.172.0': resolution: {integrity: sha512-LrUtP3FEG26Zg5WiF0nbg8VoXiKokBLTcqM2iLvM9vzcfEiYmmBAPGdBgV0OYx9fvWlY3R/3ERTZcD9X5sc0NA==} - '@types/throttle-debounce@5.0.2': - resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==} - - '@types/topojson-client@3.1.5': - resolution: {integrity: sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==} - - '@types/topojson-server@3.0.4': - resolution: {integrity: sha512-5+ieK8ePfP+K2VH6Vgs1VCt+fO1U8XZHj0UsF+NktaF0DavAo1q3IvCBXgokk/xmtvoPltSUs6vxuR/zMdOE1g==} - - '@types/topojson-simplify@3.0.3': - resolution: {integrity: sha512-sBO5UZ0O2dB0bNwo0vut2yLHhj3neUGi9uL7/ROdm8Gs6dtt4jcB9OGDKr+M2isZwQM2RuzVmifnMZpxj4IGNw==} - - '@types/topojson-specification@1.0.5': - resolution: {integrity: sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==} - - '@types/topojson@3.2.6': - resolution: {integrity: sha512-ppfdlxjxofWJ66XdLgIlER/85RvpGyfOf8jrWf+3kVIjEatFxEZYD/Ea83jO672Xu1HRzd/ghwlbcZIUNHTskw==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -3937,9 +2777,6 @@ packages: '@types/webxr@0.5.24': resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - '@types/whatwg-mimetype@3.0.2': - resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} - '@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} @@ -4004,21 +2841,6 @@ packages: peerDependencies: vue: '>=3.5.18' - '@unovis/dagre-layout@0.8.8-2': - resolution: {integrity: sha512-ZfDvfcYtzzhZhgKZty8XDi+zQIotfRqfNVF5M3dFQ9d9C5MTaRdbeBnPUkNrmlLJGgQ42HMOE2ajZLfm2VlRhg==} - - '@unovis/graphlibrary@2.2.0-2': - resolution: {integrity: sha512-HeEzpd/vDyWiIJt0rnh+2ICXUIuF2N0+Z9OJJiKg0DB+eFUcD+bk+9QPhYHwkFwfxdjDA9fHi1DZ/O/bbV58Nw==} - - '@unovis/ts@1.6.7': - resolution: {integrity: sha512-CXmr+EQQyba9vqcyhvc963y06agBvaX0ut+lylTSUo4A/t1YYdrFQFKUULasdVY6Pe+OK5xveZOlJrYDiPOX3A==} - - '@unovis/vue@1.6.7': - resolution: {integrity: sha512-iyYdwwI8Tm8Kyb3aUvG3GVmId6gcmw8EY2Qbaim1W4uqktDYViFzJXIjLPbNir4ju+ziXmaxM2sfhfEC3t3TYw==} - peerDependencies: - '@unovis/ts': 1.6.7 - vue: ^3 - '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -4153,35 +2975,6 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 vue: ^3.2.25 - '@vitest/expect@3.2.7': - resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} - - '@vitest/mocker@3.2.7': - resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@3.2.7': - resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} - - '@vitest/runner@3.2.7': - resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} - - '@vitest/snapshot@3.2.7': - resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} - - '@vitest/spy@3.2.7': - resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} - - '@vitest/utils@3.2.7': - resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} - '@volar/language-core@2.4.15': resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} @@ -4196,6 +2989,11 @@ packages: '@volar/typescript@2.4.15': resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true '@vue-macros/common@3.1.2': resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} @@ -4315,16 +3113,6 @@ packages: '@vue/shared@3.5.27': resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==} - '@vue/test-utils@2.4.11': - resolution: {integrity: sha512-GDqaqZsA6m2E5vNzej0aYiIb6BX8xV9pNSbbbXKOfEYwg7ZNblVX8suyqmUBThq8VIrgAJNxn+z72hVtUeiWHA==} - peerDependencies: - '@vue/compiler-dom': 3.x - '@vue/server-renderer': 3.x - vue: 3.x - peerDependenciesMeta: - '@vue/server-renderer': - optional: true - '@vue/tsconfig@0.7.0': resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==} peerDependencies: @@ -4342,11 +3130,6 @@ packages: '@vueuse/core@12.8.2': resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} - '@vueuse/core@14.4.0': - resolution: {integrity: sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==} - peerDependencies: - vue: ^3.5.0 - '@vueuse/core@9.13.0': resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} @@ -4356,9 +3139,6 @@ packages: '@vueuse/metadata@12.8.2': resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} - '@vueuse/metadata@14.4.0': - resolution: {integrity: sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==} - '@vueuse/metadata@9.13.0': resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} @@ -4368,11 +3148,6 @@ packages: '@vueuse/shared@12.8.2': resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} - '@vueuse/shared@14.4.0': - resolution: {integrity: sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==} - peerDependencies: - vue: ^3.5.0 - '@vueuse/shared@9.13.0': resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} @@ -4394,10 +3169,6 @@ packages: '@yr/monotone-cubic-spline@1.0.3': resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==} - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -4419,15 +3190,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -4498,14 +3260,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - ast-kit@2.2.0: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} @@ -4541,10 +3295,6 @@ packages: react-native-b4a: optional: true - babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -4570,21 +3320,12 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - birpc@0.2.14: - resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==} - birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} - blake3-wasm@2.1.5: - resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - bowser@2.14.1: - resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -4657,10 +3398,6 @@ packages: caniuse-lite@1.0.30001767: resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==} - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -4672,10 +3409,6 @@ packages: charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - chevrotain@7.1.1: resolution: {integrity: sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==} @@ -4708,12 +3441,6 @@ packages: citty@0.2.0: resolution: {integrity: sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA==} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -4726,10 +3453,6 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -4741,13 +3464,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} @@ -4755,10 +3471,6 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -4801,16 +3513,10 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -4820,10 +3526,6 @@ packages: cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} - copy-anything@4.0.5: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} @@ -4837,10 +3539,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -4896,9 +3594,6 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} - csscolorparser@1.0.3: - resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} - cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -4932,156 +3627,6 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - d3-array@2.12.1: - resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-axis@3.0.0: - resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} - engines: {node: '>=12'} - - d3-brush@3.0.0: - resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} - engines: {node: '>=12'} - - d3-chord@3.0.1: - resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} - engines: {node: '>=12'} - - d3-collection@1.0.7: - resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-contour@4.0.2: - resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} - engines: {node: '>=12'} - - d3-delaunay@6.0.4: - resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} - engines: {node: '>=12'} - - d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} - engines: {node: '>=12'} - - d3-drag@3.0.0: - resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} - engines: {node: '>=12'} - - d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} - engines: {node: '>=12'} - hasBin: true - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} - engines: {node: '>=12'} - - d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} - engines: {node: '>=12'} - - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-geo-projection@4.0.0: - resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==} - engines: {node: '>=12'} - hasBin: true - - d3-geo@3.1.1: - resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} - engines: {node: '>=12'} - - d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} - engines: {node: '>=12'} - - d3-interpolate-path@2.3.0: - resolution: {integrity: sha512-tZYtGXxBmbgHsIc9Wms6LS5u4w6KbP8C09a4/ZYc4KLMYYqub57rRBUgpUr2CIarIrJEpdAWWxWQvofgaMpbKQ==} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@1.0.9: - resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-polygon@3.0.1: - resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} - engines: {node: '>=12'} - - d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} - engines: {node: '>=12'} - - d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} - engines: {node: '>=12'} - - d3-sankey@0.12.3: - resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} - - d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-selection@3.0.0: - resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} - engines: {node: '>=12'} - - d3-shape@1.3.7: - resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - d3-transition@3.0.1: - resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} - engines: {node: '>=12'} - peerDependencies: - d3-selection: 2 - 3 - - d3-zoom@3.0.0: - resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} - engines: {node: '>=12'} - - d3@7.9.0: - resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} - engines: {node: '>=12'} - dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} @@ -5126,10 +3671,6 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -5162,9 +3703,6 @@ packages: defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} - delaunator@5.1.0: - resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -5242,26 +3780,15 @@ packages: duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - earcut@2.2.4: - resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - editorconfig@1.0.7: - resolution: {integrity: sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==} - engines: {node: '>=14'} - hasBin: true - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} electron-to-chromium@1.5.286: resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} - elkjs@0.10.2: - resolution: {integrity: sha512-Yx3ORtbAFrXelYkAy2g0eYyVY8QG0XEmGdQXmy0eithKKjbWRfl3Xe884lfkszfBF6UKyIy4LwfcZ3AZc8oxFw==} - emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5308,9 +3835,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} @@ -5330,11 +3854,6 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.25.4: - resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -5345,11 +3864,6 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} - engines: {node: '>=18'} - hasBin: true - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -5487,6 +4001,7 @@ packages: eslint@9.39.2: resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -5547,14 +4062,6 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} - exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - - expect-type@1.4.0: - resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} - engines: {node: '>=12.0.0'} - exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -5612,9 +4119,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -5704,13 +4208,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - geojson-vt@3.2.1: - resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} - - geojson@0.5.0: - resolution: {integrity: sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==} - engines: {node: '>= 0.10'} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -5730,10 +4227,6 @@ packages: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} engines: {node: '>=6'} - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} @@ -5762,9 +4255,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -5778,10 +4268,6 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} - global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -5825,10 +4311,6 @@ packages: h3@1.15.5: resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==} - happy-dom@18.0.1: - resolution: {integrity: sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==} - engines: {node: '>=20.0.0'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -5857,13 +4339,9 @@ packages: engines: {node: '>=12.0.0'} highlightjs-mcfunction@https://codeload.github.com/modrinth/better-highlightjs-mcfunction/tar.gz/aa999b763fd792ffb950d28347eeb6811c83ea8e: - resolution: {tarball: https://codeload.github.com/modrinth/better-highlightjs-mcfunction/tar.gz/aa999b763fd792ffb950d28347eeb6811c83ea8e} + resolution: {gitHosted: true, integrity: sha512-pCS2yd9Polaee8CnfjSS41H1Zk4Qr3SwNHl/wjV7qZU4Plc2rsbrIvffcCCKU/QZcwPOuP9bIIefstjMn+zU5g==, tarball: https://codeload.github.com/modrinth/better-highlightjs-mcfunction/tar.gz/aa999b763fd792ffb950d28347eeb6811c83ea8e} version: 1.0.0 - hono@4.13.1: - resolution: {integrity: sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==} - engines: {node: '>=16.9.0'} - hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -5873,12 +4351,6 @@ packages: hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - howxm-js@0.0.10: - resolution: {integrity: sha512-cKuzdZoQiTheKlOgnb5omMv/K/pk3naxXLMbE78CeLn/WzrCC6Y1vMoWDrMFs7cwuu7c0rspI4LAY9JRlw+4Nw==} - engines: {node: '>=8', npm: '>=5'} - peerDependencies: - react: '>=16.9.0' - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -5906,10 +4378,6 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -5953,9 +4421,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@4.1.1: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5964,13 +4429,6 @@ packages: resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} engines: {node: ^20.17.0 || >=22.9.0} - internmap@1.0.1: - resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} - - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - intl-messageformat@10.7.18: resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==} @@ -5987,9 +4445,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.4: - resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -6109,17 +4564,6 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.2.8: - resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==} - - js-beautify@1.15.4: - resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} - engines: {node: '>=14'} - hasBin: true - - js-cookie@3.0.8: - resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -6167,9 +4611,6 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - kdbush@3.0.0: - resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==} - keep-a-changelog@3.0.2: resolution: {integrity: sha512-MKk4RWduGopP7MoA8bkzdXQk9CV6cbqNjMzpClM/mA2kT+jsbvO6co2h3UuYPe6/bX/UITemzLBNEanplrIOmQ==} hasBin: true @@ -6177,10 +4618,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -6206,9 +4643,6 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} - leaflet@1.7.1: - resolution: {integrity: sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==} - levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -6397,9 +4831,6 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.18.1: - resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} - lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} @@ -6418,9 +4849,6 @@ packages: lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} - loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -6434,11 +4862,6 @@ packages: lucide-static@0.562.0: resolution: {integrity: sha512-TM2vNVOEsO3+ijmno7n/VmxUo0Shr9OXC/UqZc5n4xEVyXX4E4NVvXoRPAZiSsIsdvlQ7alGOcIC/QGtR+OgUQ==} - lucide-vue-next@0.468.0: - resolution: {integrity: sha512-quV/6T8YB1XK0VOEnebg3Byd8Rsan5/m95cvjnuHV4vcS3qEnLAybkrSh0hk3ppavx+V7R1PjNW+mGDvcBdz4A==} - peerDependencies: - vue: '>=3.0.1' - magic-regexp@0.10.0: resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==} @@ -6452,9 +4875,6 @@ packages: magicast@0.5.1: resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} - maplibre-gl@2.4.0: - resolution: {integrity: sha512-csNFylzntPmHWidczfgCZpvbTSmhaWvLRj9e1ezUDBEPizGgshgm3ea1T5TCNEEBq0roauu7BPuRZjA3wO4KqA==} - markdown-it@13.0.2: resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==} hasBin: true @@ -6520,11 +4940,6 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - mime@4.1.0: resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} engines: {node: '>=16'} @@ -6538,15 +4953,6 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - miniflare@4.20250906.0: - resolution: {integrity: sha512-T/RWn1sa0ien80s6NjU+Un/tj12gR6wqScZoiLeMJDD4/fK0UXfnbWXJDubnUED8Xjm7RPQ5ESYdE+mhPmMtuQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - miniflare@5.20260801.0-alpha: - resolution: {integrity: sha512-AfMrnQbJg81ESsGkGhOkHBtwTqCG+mosR+3GE+qDrhF1I/ieIvgg3ICxNyBvgHBZ3iapy6cysBQHNPykkzrfgw==} - engines: {node: '>=22.0.0'} - minimatch@10.1.2: resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} engines: {node: 20 || >=22} @@ -6562,9 +4968,6 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -6607,9 +5010,6 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - murmurhash-js@1.0.0: - resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} - mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -6676,11 +5076,6 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - nopt@7.2.1: - resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - nopt@8.1.0: resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} engines: {node: ^18.17.0 || >=20.5.0} @@ -6885,27 +5280,12 @@ packages: resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} engines: {node: 20 || >=22} - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - - pbf@3.3.0: - resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==} - hasBin: true - perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -7273,12 +5653,6 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - - protocol-buffers-schema@3.6.1: - resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==} - protocols@2.0.2: resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} @@ -7312,9 +5686,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - quickselect@2.0.0: - resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} - radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -7400,11 +5771,6 @@ packages: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true - reka-ui@2.10.1: - resolution: {integrity: sha512-drcOQ4rQtDYAcGCsyQBqQg8QQ+H3B+zDaMJU0h8KPEPMa7g9BHu3zcOi4OB39XJSWizceFoNO0Z9tctSGLOXqg==} - peerDependencies: - vue: '>= 3.4.0' - remove-accents@0.5.0: resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} @@ -7426,9 +5792,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve-protobuf-schema@2.1.0: - resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} - resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -7441,9 +5804,6 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - robust-predicates@3.0.3: - resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rolldown@1.0.0-rc.12: resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7474,9 +5834,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7552,14 +5909,6 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - sharp@0.35.2: - resolution: {integrity: sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==} - engines: {node: '>=20.9.0'} - shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -7596,9 +5945,6 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -7609,9 +5955,6 @@ packages: simple-git@3.30.0: resolution: {integrity: sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==} - simple-swizzle@0.2.4: - resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} - sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -7636,10 +5979,6 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -7679,9 +6018,6 @@ packages: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} @@ -7701,10 +6037,6 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} - streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -7761,9 +6093,6 @@ packages: '@types/node': optional: true - striptags@3.2.0: - resolution: {integrity: sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==} - structured-clone-es@1.0.0: resolution: {integrity: sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==} @@ -7776,17 +6105,11 @@ packages: peerDependencies: postcss: ^8.4.32 - stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true - supercluster@7.1.5: - resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==} - superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} @@ -7825,9 +6148,6 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tailwind-merge@2.6.1: - resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} - tailwindcss@3.4.19: resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} engines: {node: '>=14.0.0'} @@ -7846,6 +6166,7 @@ packages: tar@7.5.7: resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me terser@5.46.0: resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} @@ -7879,28 +6200,15 @@ packages: peerDependencies: three: '>=0.128.0' - three@0.135.0: - resolution: {integrity: sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ==} - three@0.172.0: resolution: {integrity: sha512-6HMgMlzU97MsV7D/tY8Va38b83kz8YJX+BefKjspMNAv0Vx6dxMogHOrnRl/sbMIs3BPUKijPqDqJ/+UwJbIow==} - throttle-debounce@5.0.2: - resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} - engines: {node: '>=12.22'} - through2@0.6.5: resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -7909,21 +6217,6 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyqueue@2.0.3: - resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -7932,10 +6225,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - topojson-client@3.1.0: - resolution: {integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==} - hasBin: true - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -8042,23 +6331,9 @@ packages: unctx@2.5.0: resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.28.0: - resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} - engines: {node: '>=20.18.1'} - - undici@7.29.0: - resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} - engines: {node: '>=20.18.1'} - - unenv@2.0.0-rc.21: - resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==} - unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} @@ -8203,11 +6478,6 @@ packages: peerDependencies: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - vite-node@5.3.0: resolution: {integrity: sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -8265,6 +6535,7 @@ packages: engines: {node: '>=v14.21.3'} peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: '*' vite-plugin-vue-inspector@6.0.0: resolution: {integrity: sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==} @@ -8396,40 +6667,9 @@ packages: yaml: optional: true - vitest@3.2.7: - resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.7 - '@vitest/ui': 3.2.7 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - vt-pbf@3.1.3: - resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} - vue-bundle-renderer@2.2.0: resolution: {integrity: sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==} @@ -8529,10 +6769,6 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -8550,45 +6786,10 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerd@1.20250906.0: - resolution: {integrity: sha512-ryVyEaqXPPsr/AxccRmYZZmDAkfQVjhfRqrNTlEeN8aftBk6Ca1u7/VqmfOayjCXrA+O547TauebU+J3IpvFXw==} - engines: {node: '>=16'} - hasBin: true - - workerd@1.20260801.1: - resolution: {integrity: sha512-/g9JGTyqnHtoIscpBHqKD8swE2V4StBs2i69PmLiOhH45OP95jCFICl4F1hKlgN57rqfni5LiCitttoX5OOkVA==} - engines: {node: '>=16'} - hasBin: true - - wrangler@4.119.0: - resolution: {integrity: sha512-ookClf+zly4DTc8pBMNrwGQzZKH8IpIYTXkjDw3XS7ZvBQ5mLYH6eOvfD5BEpk3U63zTbv91WRlo1UeRSKXa0g==} - engines: {node: '>=22.0.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^5.20260801.1 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - - wrangler@4.35.0: - resolution: {integrity: sha512-HbyXtbrh4Fi3mU8ussY85tVdQ74qpVS1vctUgaPc+bPrXBTqfDLkZ6VRtHAVF/eBhz4SFmhJtCQpN1caY2Ak8A==} - engines: {node: '>=18.0.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^4.20250906.0 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -8600,18 +6801,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - 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 - ws@8.21.0: resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} @@ -8660,10 +6849,6 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@1.10.3: - resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} - engines: {node: '>= 6'} - yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -8684,9 +6869,6 @@ packages: youch-core@0.3.3: resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} - youch@4.1.0-beta.10: - resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} - youch@4.1.0-beta.13: resolution: {integrity: sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g==} @@ -8694,183 +6876,12 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod@3.22.3: - resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - snapshots: '@alloc/quick-lru@5.2.0': {} '@alvarosabu/utils@3.2.0': {} - '@aws-sdk/checksums@3.1000.26': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/client-s3@3.1105.0': - dependencies: - '@aws-sdk/checksums': 3.1000.26 - '@aws-sdk/core': 3.977.6 - '@aws-sdk/credential-provider-node': 3.972.78 - '@aws-sdk/middleware-sdk-s3': 3.972.72 - '@aws-sdk/signature-v4-multi-region': 3.996.43 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/fetch-http-handler': 5.6.13 - '@smithy/node-http-handler': 4.9.13 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/core@3.977.6': - dependencies: - '@aws-sdk/types': 3.974.2 - '@aws-sdk/xml-builder': 3.972.37 - '@aws/lambda-invoke-store': 0.3.0 - '@smithy/core': 3.31.1 - '@smithy/signature-v4': 5.6.12 - '@smithy/types': 4.16.1 - bowser: 2.14.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-env@3.972.67': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-http@3.972.69': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/fetch-http-handler': 5.6.13 - '@smithy/node-http-handler': 4.9.13 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-ini@3.973.12': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/credential-provider-env': 3.972.67 - '@aws-sdk/credential-provider-http': 3.972.69 - '@aws-sdk/credential-provider-login': 3.972.74 - '@aws-sdk/credential-provider-process': 3.972.67 - '@aws-sdk/credential-provider-sso': 3.973.11 - '@aws-sdk/credential-provider-web-identity': 3.972.73 - '@aws-sdk/nested-clients': 3.997.41 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/credential-provider-imds': 4.4.16 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-login@3.972.74': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/nested-clients': 3.997.41 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-node@3.972.78': - dependencies: - '@aws-sdk/credential-provider-env': 3.972.67 - '@aws-sdk/credential-provider-http': 3.972.69 - '@aws-sdk/credential-provider-ini': 3.973.12 - '@aws-sdk/credential-provider-process': 3.972.67 - '@aws-sdk/credential-provider-sso': 3.973.11 - '@aws-sdk/credential-provider-web-identity': 3.972.73 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/credential-provider-imds': 4.4.16 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-process@3.972.67': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-sso@3.973.11': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/nested-clients': 3.997.41 - '@aws-sdk/token-providers': 3.1103.0 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-web-identity@3.972.73': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/nested-clients': 3.997.41 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/middleware-sdk-s3@3.972.72': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/signature-v4-multi-region': 3.996.43 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/nested-clients@3.997.41': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/signature-v4-multi-region': 3.996.43 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/fetch-http-handler': 5.6.13 - '@smithy/node-http-handler': 4.9.13 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/signature-v4-multi-region@3.996.43': - dependencies: - '@aws-sdk/types': 3.974.2 - '@smithy/signature-v4': 5.6.12 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/token-providers@3.1103.0': - dependencies: - '@aws-sdk/core': 3.977.6 - '@aws-sdk/nested-clients': 3.997.41 - '@aws-sdk/types': 3.974.2 - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/types@3.974.2': - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws-sdk/xml-builder@3.972.37': - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@aws/lambda-invoke-store@0.3.0': {} - '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -8885,20 +6896,20 @@ snapshots: '@babel/compat-data@7.29.0': {} - '@babel/core@7.29.0': + '@babel/core@7.29.0(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helpers': 7.28.6 '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8937,28 +6948,28 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) + '@babel/traverse': 7.29.0(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.8 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.8(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -8967,33 +6978,33 @@ snapshots: '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.28.5(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@10.2.2) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.28.6(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-module-imports': 7.28.6(supports-color@10.2.2) '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -9009,34 +7020,34 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.27.1(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@10.2.2) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -9064,53 +7075,51 @@ snapshots: dependencies: '@babel/types': 7.29.8 - '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.0) + '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.0(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.0(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.0(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@10.2.2) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - '@babel/runtime@7.29.7': {} - '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -9123,7 +7132,7 @@ snapshots: '@babel/parser': 7.29.8 '@babel/types': 7.29.8 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.0(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.0 @@ -9131,11 +7140,11 @@ snapshots: '@babel/parser': 7.29.0 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/traverse@7.29.8': + '@babel/traverse@7.29.8(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 @@ -9143,7 +7152,7 @@ snapshots: '@babel/parser': 7.29.8 '@babel/template': 7.29.7 '@babel/types': 7.29.8 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -9182,75 +7191,8 @@ snapshots: '@clack/core': 1.1.0 sisteransi: 1.0.5 - '@cloudflare/kv-asset-handler@0.4.0': - dependencies: - mime: 3.0.0 - '@cloudflare/kv-asset-handler@0.4.2': {} - '@cloudflare/kv-asset-handler@0.5.0': {} - - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260801.1)': - dependencies: - unenv: 2.0.0-rc.24 - optionalDependencies: - workerd: 1.20260801.1 - - '@cloudflare/unenv-preset@2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0)': - dependencies: - unenv: 2.0.0-rc.21 - optionalDependencies: - workerd: 1.20250906.0 - - '@cloudflare/vitest-pool-workers@0.8.71(@cloudflare/workers-types@5.20260804.1)(@vitest/runner@3.2.7)(@vitest/snapshot@3.2.7)(vitest@3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0))': - dependencies: - '@vitest/runner': 3.2.7 - '@vitest/snapshot': 3.2.7 - birpc: 0.2.14 - cjs-module-lexer: 1.4.3 - devalue: 5.6.2 - miniflare: 4.20250906.0 - semver: 7.8.5 - vitest: 3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - wrangler: 4.35.0(@cloudflare/workers-types@5.20260804.1) - zod: 3.25.76 - transitivePeerDependencies: - - '@cloudflare/workers-types' - - bufferutil - - utf-8-validate - - '@cloudflare/workerd-darwin-64@1.20250906.0': - optional: true - - '@cloudflare/workerd-darwin-64@1.20260801.1': - optional: true - - '@cloudflare/workerd-darwin-arm64@1.20250906.0': - optional: true - - '@cloudflare/workerd-darwin-arm64@1.20260801.1': - optional: true - - '@cloudflare/workerd-linux-64@1.20250906.0': - optional: true - - '@cloudflare/workerd-linux-64@1.20260801.1': - optional: true - - '@cloudflare/workerd-linux-arm64@1.20250906.0': - optional: true - - '@cloudflare/workerd-linux-arm64@1.20260801.1': - optional: true - - '@cloudflare/workerd-windows-64@1.20250906.0': - optional: true - - '@cloudflare/workerd-windows-64@1.20260801.1': - optional: true - - '@cloudflare/workers-types@5.20260804.1': {} - '@codemirror/autocomplete@6.20.0': dependencies: '@codemirror/language': 6.12.1 @@ -9331,17 +7273,13 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@crowdin/crowdin-api-client@1.55.2': + '@crowdin/crowdin-api-client@1.55.2(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - axios: 1.16.1 + axios: 1.16.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - debug - supports-color - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - '@dxup/nuxt@0.2.2(magicast@0.5.1)': dependencies: '@dxup/unimport': 0.1.2 @@ -9365,70 +7303,11 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.8.1': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 optional: true - '@emotion/babel-plugin@11.13.5': - dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/runtime': 7.29.7 - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/serialize': 1.3.3 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 - transitivePeerDependencies: - - supports-color - - '@emotion/cache@11.14.0': - dependencies: - '@emotion/memoize': 0.9.0 - '@emotion/sheet': 1.4.0 - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - stylis: 4.2.0 - - '@emotion/css@11.13.5': - dependencies: - '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - '@emotion/sheet': 1.4.0 - '@emotion/utils': 1.4.2 - transitivePeerDependencies: - - supports-color - - '@emotion/hash@0.9.2': {} - - '@emotion/memoize@0.9.0': {} - - '@emotion/serialize@1.3.3': - dependencies: - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/unitless': 0.10.0 - '@emotion/utils': 1.4.2 - csstype: 3.2.3 - - '@emotion/sheet@1.4.0': {} - - '@emotion/unitless@0.10.0': {} - - '@emotion/utils@1.4.2': {} - - '@emotion/weak-memoize@0.4.0': {} - '@es-joy/jsdoccomment@0.50.2': dependencies: '@types/estree': 1.0.8 @@ -9440,409 +7319,256 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.25.4': - optional: true - '@esbuild/aix-ppc64@0.27.2': optional: true '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/aix-ppc64@0.28.1': - optional: true - '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.25.4': - optional: true - '@esbuild/android-arm64@0.27.2': optional: true '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm64@0.28.1': - optional: true - '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.25.4': - optional: true - '@esbuild/android-arm@0.27.2': optional: true '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-arm@0.28.1': - optional: true - '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.25.4': - optional: true - '@esbuild/android-x64@0.27.2': optional: true '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/android-x64@0.28.1': - optional: true - '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.25.4': - optional: true - '@esbuild/darwin-arm64@0.27.2': optional: true '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.28.1': - optional: true - '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.25.4': - optional: true - '@esbuild/darwin-x64@0.27.2': optional: true '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/darwin-x64@0.28.1': - optional: true - '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.25.4': - optional: true - '@esbuild/freebsd-arm64@0.27.2': optional: true '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.28.1': - optional: true - '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.25.4': - optional: true - '@esbuild/freebsd-x64@0.27.2': optional: true '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.28.1': - optional: true - '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.25.4': - optional: true - '@esbuild/linux-arm64@0.27.2': optional: true '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm64@0.28.1': - optional: true - '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.25.4': - optional: true - '@esbuild/linux-arm@0.27.2': optional: true '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-arm@0.28.1': - optional: true - '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.25.4': - optional: true - '@esbuild/linux-ia32@0.27.2': optional: true '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-ia32@0.28.1': - optional: true - '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.25.4': - optional: true - '@esbuild/linux-loong64@0.27.2': optional: true '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-loong64@0.28.1': - optional: true - '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.25.4': - optional: true - '@esbuild/linux-mips64el@0.27.2': optional: true '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-mips64el@0.28.1': - optional: true - '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.25.4': - optional: true - '@esbuild/linux-ppc64@0.27.2': optional: true '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-ppc64@0.28.1': - optional: true - '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.25.4': - optional: true - '@esbuild/linux-riscv64@0.27.2': optional: true '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.28.1': - optional: true - '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.25.4': - optional: true - '@esbuild/linux-s390x@0.27.2': optional: true '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-s390x@0.28.1': - optional: true - '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.25.4': - optional: true - '@esbuild/linux-x64@0.27.2': optional: true '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/linux-x64@0.28.1': - optional: true - - '@esbuild/netbsd-arm64@0.25.4': - optional: true - '@esbuild/netbsd-arm64@0.27.2': optional: true '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.28.1': - optional: true - '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.25.4': - optional: true - '@esbuild/netbsd-x64@0.27.2': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.28.1': - optional: true - - '@esbuild/openbsd-arm64@0.25.4': - optional: true - '@esbuild/openbsd-arm64@0.27.2': optional: true '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.28.1': - optional: true - '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.25.4': - optional: true - '@esbuild/openbsd-x64@0.27.2': optional: true '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.28.1': - optional: true - '@esbuild/openharmony-arm64@0.27.2': optional: true '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/openharmony-arm64@0.28.1': - optional: true - '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.25.4': - optional: true - '@esbuild/sunos-x64@0.27.2': optional: true '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/sunos-x64@0.28.1': - optional: true - '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.25.4': - optional: true - '@esbuild/win32-arm64@0.27.2': optional: true '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-arm64@0.28.1': - optional: true - '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.25.4': - optional: true - '@esbuild/win32-ia32@0.27.2': optional: true '@esbuild/win32-ia32@0.27.3': optional: true - '@esbuild/win32-ia32@0.28.1': - optional: true - '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.25.4': - optional: true - '@esbuild/win32-x64@0.27.2': optional: true '@esbuild/win32-x64@0.27.3': optional: true - '@esbuild/win32-x64@0.28.1': - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))': dependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))': dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.2(jiti@1.21.7))': + '@eslint/compat@1.4.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))': dependencies: '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) - '@eslint/compat@1.4.1(eslint@9.39.2(jiti@2.6.1))': + '@eslint/compat@1.4.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))': dependencies: '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.21.1(supports-color@10.2.2)': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -9855,10 +7581,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.3(supports-color@10.2.2)': dependencies: ajv: 6.12.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -9882,32 +7608,12 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.10 - '@floating-ui/core@1.8.0': - dependencies: - '@floating-ui/utils': 0.2.12 - '@floating-ui/dom@1.1.1': dependencies: '@floating-ui/core': 1.7.4 - '@floating-ui/dom@1.8.0': - dependencies: - '@floating-ui/core': 1.8.0 - '@floating-ui/utils': 0.2.12 - '@floating-ui/utils@0.2.10': {} - '@floating-ui/utils@0.2.12': {} - - '@floating-ui/vue@1.1.11(vue@3.5.27(typescript@5.9.3))': - dependencies: - '@floating-ui/dom': 1.8.0 - '@floating-ui/utils': 0.2.12 - vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - '@formatjs/cli@6.12.2(@vue/compiler-core@3.5.27)(vue@3.5.27(typescript@5.9.3))': optionalDependencies: '@vue/compiler-core': 3.5.27 @@ -9999,195 +7705,6 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/colour@1.1.0': {} - - '@img/sharp-darwin-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 - optional: true - - '@img/sharp-darwin-arm64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.3.1 - optional: true - - '@img/sharp-darwin-x64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 - optional: true - - '@img/sharp-darwin-x64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.3.1 - optional: true - - '@img/sharp-freebsd-wasm32@0.35.2': - dependencies: - '@img/sharp-wasm32': 0.35.2 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.0.4': - optional: true - - '@img/sharp-libvips-darwin-arm64@1.3.1': - optional: true - - '@img/sharp-libvips-darwin-x64@1.0.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.3.1': - optional: true - - '@img/sharp-libvips-linux-arm64@1.0.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.3.1': - optional: true - - '@img/sharp-libvips-linux-arm@1.0.5': - optional: true - - '@img/sharp-libvips-linux-arm@1.3.1': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.3.1': - optional: true - - '@img/sharp-libvips-linux-riscv64@1.3.1': - optional: true - - '@img/sharp-libvips-linux-s390x@1.0.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.3.1': - optional: true - - '@img/sharp-libvips-linux-x64@1.0.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.3.1': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.3.1': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.3.1': - optional: true - - '@img/sharp-linux-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 - optional: true - - '@img/sharp-linux-arm64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.3.1 - optional: true - - '@img/sharp-linux-arm@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 - optional: true - - '@img/sharp-linux-arm@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.3.1 - optional: true - - '@img/sharp-linux-ppc64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.3.1 - optional: true - - '@img/sharp-linux-riscv64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.3.1 - optional: true - - '@img/sharp-linux-s390x@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 - optional: true - - '@img/sharp-linux-s390x@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.3.1 - optional: true - - '@img/sharp-linux-x64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 - optional: true - - '@img/sharp-linux-x64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.3.1 - optional: true - - '@img/sharp-linuxmusl-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - optional: true - - '@img/sharp-linuxmusl-arm64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 - optional: true - - '@img/sharp-linuxmusl-x64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.35.2': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.3.1 - optional: true - - '@img/sharp-wasm32@0.33.5': - dependencies: - '@emnapi/runtime': 1.11.3 - optional: true - - '@img/sharp-wasm32@0.35.2': - dependencies: - '@emnapi/runtime': 1.11.3 - optional: true - - '@img/sharp-webcontainers-wasm32@0.35.2': - dependencies: - '@img/sharp-wasm32': 0.35.2 - optional: true - - '@img/sharp-win32-arm64@0.35.2': - optional: true - - '@img/sharp-win32-ia32@0.33.5': - optional: true - - '@img/sharp-win32-ia32@0.35.2': - optional: true - - '@img/sharp-win32-x64@0.33.5': - optional: true - - '@img/sharp-win32-x64@0.35.2': - optional: true - - '@internationalized/date@3.12.3': - dependencies: - '@swc/helpers': 0.5.23 - - '@internationalized/number@3.6.7': - dependencies: - '@swc/helpers': 0.5.23 - '@intlify/core-base@10.0.8': dependencies: '@intlify/message-compiler': 10.0.8 @@ -10245,16 +7762,9 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.9': + '@kwsites/file-exists@1.1.1(supports-color@10.2.2)': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@juggle/resize-observer@3.4.0': {} - - '@kwsites/file-exists@1.1.1': - dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -10295,20 +7805,11 @@ snapshots: '@lobehub/icons-static-svg@1.94.0': {} - '@mapbox/geojson-rewind@0.5.2': - dependencies: - get-stream: 6.0.1 - minimist: 1.2.8 - - '@mapbox/jsonlint-lines-primitives@2.0.3': {} - - '@mapbox/mapbox-gl-supported@2.0.1': {} - - '@mapbox/node-pre-gyp@2.0.3': + '@mapbox/node-pre-gyp@2.0.3(supports-color@10.2.2)': dependencies: consola: 3.4.2 detect-libc: 2.1.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) node-fetch: 2.7.0 nopt: 8.1.0 semver: 7.8.5 @@ -10317,18 +7818,6 @@ snapshots: - encoding - supports-color - '@mapbox/point-geometry@0.1.0': {} - - '@mapbox/tiny-sdf@2.2.0': {} - - '@mapbox/unitbezier@0.0.1': {} - - '@mapbox/vector-tile@1.3.1': - dependencies: - '@mapbox/point-geometry': 0.1.0 - - '@mapbox/whoots-js@3.1.0': {} - '@marijn/find-cluster-break@1.0.2': {} '@napi-rs/wasm-runtime@0.2.12': @@ -10341,7 +7830,7 @@ snapshots: '@napi-rs/wasm-runtime@1.1.1': dependencies: '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 + '@emnapi/runtime': 1.11.3 '@tybys/wasm-util': 0.10.1 optional: true @@ -10357,7 +7846,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@nuxt/cli@3.32.0(cac@6.7.14)(magicast@0.5.1)': + '@nuxt/cli@3.32.0(cac@6.7.14)(magicast@0.5.1)(supports-color@10.2.2)': dependencies: '@bomb.sh/tab': 0.0.11(cac@6.7.14)(citty@0.1.6) '@clack/prompts': 1.0.0-alpha.9 @@ -10366,7 +7855,7 @@ snapshots: confbox: 0.2.2 consola: 3.4.2 copy-paste: 2.2.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) defu: 6.1.4 exsolve: 1.0.8 fuse.js: 7.1.0 @@ -10394,11 +7883,11 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@3.1.1(magicast@0.5.1)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))': + '@nuxt/devtools-kit@3.1.1(magicast@0.5.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))': dependencies: '@nuxt/kit': 4.3.0(magicast@0.5.1) execa: 8.0.1 - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) transitivePeerDependencies: - magicast @@ -10413,12 +7902,12 @@ snapshots: prompts: 2.4.2 semver: 7.8.5 - '@nuxt/devtools@3.1.1(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': + '@nuxt/devtools@3.1.1(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) '@nuxt/devtools-wizard': 3.1.1 '@nuxt/kit': 4.3.0(magicast@0.5.1) - '@vue/devtools-core': 8.0.5(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + '@vue/devtools-core': 8.0.5(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) '@vue/devtools-kit': 8.0.5 birpc: 2.9.0 consola: 3.4.2 @@ -10439,13 +7928,13 @@ snapshots: perfect-debounce: 2.1.0 pkg-types: 2.3.0 semver: 7.8.5 - simple-git: 3.30.0 + simple-git: 3.30.0(supports-color@10.2.2) sirv: 3.0.2 structured-clone-es: 1.0.0 tinyglobby: 0.2.15 - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-plugin-inspect: 11.3.3(@nuxt/kit@4.3.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) - vite-plugin-vue-tracer: 1.2.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite-plugin-inspect: 11.3.3(@nuxt/kit@4.3.0(magicast@0.5.1))(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-vue-tracer: 1.2.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) which: 5.0.0 ws: 8.21.0 transitivePeerDependencies: @@ -10454,70 +7943,70 @@ snapshots: - utf-8-validate - vue - '@nuxt/eslint-config@0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@nuxt/eslint-config@0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.2 - '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) - eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@1.21.7)) + '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) + eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) eslint-flat-config-utils: 0.4.0 - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@1.21.7)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2) + eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2) + eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) + eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) + eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2) globals: 15.15.0 local-pkg: 0.5.1 pathe: 1.1.2 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node - supports-color - typescript - '@nuxt/eslint-config@0.5.7(@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)': + '@nuxt/eslint-config@0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.2 - '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@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) - eslint: 9.39.2(jiti@2.6.1) - eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@2.6.1)) + '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) + eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) eslint-flat-config-utils: 0.4.0 - eslint-plugin-import-x: 4.16.1(@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)) - eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) + eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) + eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) + eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) + eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) globals: 15.15.0 local-pkg: 0.5.1 pathe: 1.1.2 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node - supports-color - typescript - '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) transitivePeerDependencies: - supports-color - typescript - '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.54.0 - '@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-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) transitivePeerDependencies: - supports-color - typescript @@ -10552,7 +8041,7 @@ snapshots: dependencies: c12: 3.3.3(magicast@0.5.1) consola: 3.4.2 - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 errx: 0.1.0 exsolve: 1.0.8 @@ -10599,7 +8088,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/nitro-server@3.20.2(db0@0.3.4)(ioredis@5.9.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(rolldown@1.0.0-rc.12)(typescript@5.9.3)(xml2js@0.6.2)': + '@nuxt/nitro-server@3.20.2(db0@0.3.4)(ioredis@5.9.2(supports-color@10.2.2))(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(rolldown@1.0.0-rc.12)(supports-color@10.2.2)(typescript@5.9.3)(xml2js@0.6.2)': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 3.20.2(magicast@0.5.1) @@ -10616,15 +8105,15 @@ snapshots: impound: 1.0.0 klona: 2.0.6 mocked-exports: 0.1.1 - nitropack: 2.13.1(rolldown@1.0.0-rc.12)(xml2js@0.6.2) - nuxt: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) + nitropack: 2.13.1(rolldown@1.0.0-rc.12)(supports-color@10.2.2)(xml2js@0.6.2) + nuxt: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) pathe: 2.0.3 pkg-types: 2.3.0 radix3: 1.1.2 std-env: 3.10.0 ufo: 1.6.3 unctx: 2.5.0 - unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2) + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2(supports-color@10.2.2)) vue: 3.5.27(typescript@5.9.3) vue-bundle-renderer: 2.2.0 vue-devtools-stub: 0.1.0 @@ -10688,12 +8177,12 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/vite-builder@3.20.2(@types/node@24.12.2)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.32.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.27(typescript@5.9.3))(yaml@2.8.2)': + '@nuxt/vite-builder@3.20.2(@types/node@24.12.2)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.27(typescript@5.9.3))(yaml@2.8.2)': dependencies: '@nuxt/kit': 3.20.2(magicast@0.5.1) '@rollup/plugin-replace': 6.0.3(rollup@4.57.1) '@vitejs/plugin-vue': 6.0.4(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) - '@vitejs/plugin-vue-jsx': 5.1.4(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': 5.1.4(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) autoprefixer: 10.4.24(postcss@8.5.8) consola: 3.4.2 cssnano: 7.1.2(postcss@8.5.8) @@ -10709,7 +8198,7 @@ snapshots: magic-string: 0.30.21 mlly: 1.8.0 mocked-exports: 0.1.1 - nuxt: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) + nuxt: 3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2) ohash: 2.0.11 pathe: 2.0.3 perfect-debounce: 2.1.0 @@ -10722,7 +8211,7 @@ snapshots: unenv: 2.0.0-rc.24 vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vite-node: 5.3.0(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-plugin-checker: 0.12.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)) + vite-plugin-checker: 0.12.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)) vue: 3.5.27(typescript@5.9.3) vue-bundle-renderer: 2.2.0 optionalDependencies: @@ -10752,8 +8241,6 @@ snapshots: - vue-tsc - yaml - '@one-ini/wasm@0.1.1': {} - '@oxc-minify/binding-android-arm64@0.102.0': optional: true @@ -11183,47 +8670,14 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@smithy/core@3.31.1': - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@smithy/credential-provider-imds@4.4.16': - dependencies: - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@smithy/fetch-http-handler@5.6.13': - dependencies: - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@smithy/node-http-handler@4.9.13': - dependencies: - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@smithy/signature-v4@5.6.12': - dependencies: - '@smithy/core': 3.31.1 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - - '@smithy/types@4.16.1': - dependencies: - tslib: 2.8.1 - '@speed-highlight/core@1.2.14': {} '@stripe/stripe-js@7.9.0': {} - '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -11232,10 +8686,10 @@ snapshots: - supports-color - typescript - '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: - '@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-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -11263,10 +8717,6 @@ snapshots: dependencies: '@svgdotjs/svg.js': 3.2.5 - '@swc/helpers@0.5.23': - dependencies: - tslib: 2.8.1 - '@tailwindcss/container-queries@0.1.1(tailwindcss@4.1.18)': dependencies: tailwindcss: 4.1.18 @@ -11345,8 +8795,6 @@ snapshots: '@tanstack/query-core@5.90.7': {} - '@tanstack/virtual-core@3.17.7': {} - '@tanstack/vue-query@5.90.7(vue@3.5.27(typescript@5.9.3))': dependencies: '@tanstack/match-sorter-utils': 8.19.4 @@ -11355,11 +8803,6 @@ snapshots: vue: 3.5.27(typescript@5.9.3) vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) - '@tanstack/vue-virtual@3.13.35(vue@3.5.27(typescript@5.9.3))': - dependencies: - '@tanstack/virtual-core': 3.17.7 - vue: 3.5.27(typescript@5.9.3) - '@taplo/core@0.2.0': {} '@taplo/lib@0.5.0': @@ -11489,144 +8932,6 @@ snapshots: tslib: 2.8.1 optional: true - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/d3-array@3.2.2': {} - - '@types/d3-axis@3.0.6': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-brush@3.0.6': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-chord@3.0.6': {} - - '@types/d3-collection@1.0.13': {} - - '@types/d3-color@3.1.3': {} - - '@types/d3-contour@3.0.6': - dependencies: - '@types/d3-array': 3.2.2 - '@types/geojson': 7946.0.16 - - '@types/d3-delaunay@6.0.4': {} - - '@types/d3-dispatch@3.0.7': {} - - '@types/d3-drag@3.0.7': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-dsv@3.0.7': {} - - '@types/d3-ease@3.0.2': {} - - '@types/d3-fetch@3.0.7': - dependencies: - '@types/d3-dsv': 3.0.7 - - '@types/d3-force@3.0.10': {} - - '@types/d3-format@3.0.4': {} - - '@types/d3-geo@3.1.1': - dependencies: - '@types/geojson': 7946.0.16 - - '@types/d3-hierarchy@3.1.7': {} - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-path@1.0.11': {} - - '@types/d3-path@3.1.1': {} - - '@types/d3-polygon@3.0.2': {} - - '@types/d3-quadtree@3.0.6': {} - - '@types/d3-random@3.0.4': {} - - '@types/d3-sankey@0.12.5': - dependencies: - '@types/d3-shape': 1.3.12 - - '@types/d3-scale-chromatic@3.1.0': {} - - '@types/d3-scale@4.0.9': - dependencies: - '@types/d3-time': 3.0.4 - - '@types/d3-selection@3.0.11': {} - - '@types/d3-shape@1.3.12': - dependencies: - '@types/d3-path': 1.0.11 - - '@types/d3-shape@3.1.8': - dependencies: - '@types/d3-path': 3.1.1 - - '@types/d3-time-format@4.0.3': {} - - '@types/d3-time@3.0.4': {} - - '@types/d3-timer@3.0.2': {} - - '@types/d3-transition@3.0.9': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-zoom@3.0.8': - dependencies: - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - - '@types/d3@7.4.3': - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-axis': 3.0.6 - '@types/d3-brush': 3.0.6 - '@types/d3-chord': 3.0.6 - '@types/d3-color': 3.1.3 - '@types/d3-contour': 3.0.6 - '@types/d3-delaunay': 6.0.4 - '@types/d3-dispatch': 3.0.7 - '@types/d3-drag': 3.0.7 - '@types/d3-dsv': 3.0.7 - '@types/d3-ease': 3.0.2 - '@types/d3-fetch': 3.0.7 - '@types/d3-force': 3.0.10 - '@types/d3-format': 3.0.4 - '@types/d3-geo': 3.1.1 - '@types/d3-hierarchy': 3.1.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-path': 3.1.1 - '@types/d3-polygon': 3.0.2 - '@types/d3-quadtree': 3.0.6 - '@types/d3-random': 3.0.4 - '@types/d3-scale': 4.0.9 - '@types/d3-scale-chromatic': 3.1.0 - '@types/d3-selection': 3.0.11 - '@types/d3-shape': 3.1.8 - '@types/d3-time': 3.0.4 - '@types/d3-time-format': 4.0.3 - '@types/d3-timer': 3.0.2 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - - '@types/dagre@0.7.54': {} - - '@types/deep-eql@4.0.2': {} - '@types/dompurify@3.2.0': dependencies: dompurify: 3.3.1 @@ -11635,24 +8940,10 @@ snapshots: '@types/estree@1.0.8': {} - '@types/geojson@7946.0.16': {} - '@types/json-schema@7.0.15': {} - '@types/leaflet@1.7.6': - dependencies: - '@types/geojson': 7946.0.16 - '@types/linkify-it@5.0.0': {} - '@types/mapbox__point-geometry@0.1.4': {} - - '@types/mapbox__vector-tile@1.3.4': - dependencies: - '@types/geojson': 7946.0.16 - '@types/mapbox__point-geometry': 0.1.4 - '@types/pbf': 3.0.5 - '@types/markdown-it@14.1.2': dependencies: '@types/linkify-it': 5.0.0 @@ -11660,10 +8951,6 @@ snapshots: '@types/mdurl@2.0.0': {} - '@types/node@20.19.43': - dependencies: - undici-types: 6.21.0 - '@types/node@24.12.2': dependencies: undici-types: 7.16.0 @@ -11672,24 +8959,14 @@ snapshots: '@types/offscreencanvas@2019.7.3': {} - '@types/parse-json@4.0.2': {} - '@types/parse-path@7.1.0': dependencies: parse-path: 7.1.0 - '@types/pbf@3.0.5': {} - '@types/resolve@1.20.2': {} '@types/stats.js@0.17.4': {} - '@types/supercluster@5.0.3': - dependencies: - '@types/geojson': 7946.0.16 - - '@types/three@0.135.0': {} - '@types/three@0.172.0': dependencies: '@tweenjs/tween.js': 23.1.3 @@ -11699,35 +8976,6 @@ snapshots: fflate: 0.8.2 meshoptimizer: 0.18.1 - '@types/throttle-debounce@5.0.2': {} - - '@types/topojson-client@3.1.5': - dependencies: - '@types/geojson': 7946.0.16 - '@types/topojson-specification': 1.0.5 - - '@types/topojson-server@3.0.4': - dependencies: - '@types/geojson': 7946.0.16 - '@types/topojson-specification': 1.0.5 - - '@types/topojson-simplify@3.0.3': - dependencies: - '@types/geojson': 7946.0.16 - '@types/topojson-specification': 1.0.5 - - '@types/topojson-specification@1.0.5': - dependencies: - '@types/geojson': 7946.0.16 - - '@types/topojson@3.2.6': - dependencies: - '@types/geojson': 7946.0.16 - '@types/topojson-client': 3.1.5 - '@types/topojson-server': 3.0.4 - '@types/topojson-simplify': 3.0.3 - '@types/topojson-specification': 1.0.5 - '@types/trusted-types@2.0.7': optional: true @@ -11739,17 +8987,15 @@ snapshots: '@types/webxr@0.5.24': {} - '@types/whatwg-mimetype@3.0.2': {} - - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.54.0 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -11757,15 +9003,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@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/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(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/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(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/type-utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.54.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -11773,35 +9019,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(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/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.54.0 - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) 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)': + '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(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/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.54.0 - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.54.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.54.0(supports-color@10.2.2)(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 + debug: 4.4.3(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -11815,25 +9061,25 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(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@1.21.7))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + '@typescript-eslint/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(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) + '@typescript-eslint/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -11841,13 +9087,13 @@ snapshots: '@typescript-eslint/types@8.54.0': {} - '@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.54.0(supports-color@10.2.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.54.0(typescript@5.9.3) + '@typescript-eslint/project-service': 8.54.0(supports-color@10.2.2)(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 + debug: 4.4.3(supports-color@10.2.2) minimatch: 9.0.5 semver: 7.8.5 tinyglobby: 0.2.15 @@ -11856,24 +9102,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) '@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@1.21.7) + '@typescript-eslint/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) 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)': + '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) '@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-eslint/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -11889,92 +9135,6 @@ snapshots: unhead: 2.1.2 vue: 3.5.27(typescript@5.9.3) - '@unovis/dagre-layout@0.8.8-2': - dependencies: - '@unovis/graphlibrary': 2.2.0-2 - lodash-es: 4.18.1 - - '@unovis/graphlibrary@2.2.0-2': - dependencies: - lodash-es: 4.18.1 - - '@unovis/ts@1.6.7': - dependencies: - '@emotion/css': 11.13.5 - '@juggle/resize-observer': 3.4.0 - '@types/d3': 7.4.3 - '@types/d3-array': 3.2.2 - '@types/d3-axis': 3.0.6 - '@types/d3-brush': 3.0.6 - '@types/d3-chord': 3.0.6 - '@types/d3-collection': 1.0.13 - '@types/d3-color': 3.1.3 - '@types/d3-drag': 3.0.7 - '@types/d3-ease': 3.0.2 - '@types/d3-force': 3.0.10 - '@types/d3-geo': 3.1.1 - '@types/d3-hierarchy': 3.1.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-path': 3.1.1 - '@types/d3-sankey': 0.12.5 - '@types/d3-scale': 4.0.9 - '@types/d3-selection': 3.0.11 - '@types/d3-shape': 3.1.8 - '@types/d3-timer': 3.0.2 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - '@types/dagre': 0.7.54 - '@types/geojson': 7946.0.16 - '@types/leaflet': 1.7.6 - '@types/supercluster': 5.0.3 - '@types/three': 0.135.0 - '@types/throttle-debounce': 5.0.2 - '@types/topojson': 3.2.6 - '@types/topojson-client': 3.1.5 - '@types/topojson-specification': 1.0.5 - '@unovis/dagre-layout': 0.8.8-2 - '@unovis/graphlibrary': 2.2.0-2 - d3: 7.9.0 - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-collection: 1.0.7 - d3-color: 3.1.0 - d3-drag: 3.0.0 - d3-ease: 3.0.1 - d3-force: 3.0.0 - d3-geo: 3.1.1 - d3-geo-projection: 4.0.0 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-interpolate-path: 2.3.0 - d3-path: 3.1.0 - d3-sankey: 0.12.3 - d3-scale: 4.0.2 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 - elkjs: 0.10.2 - geojson: 0.5.0 - leaflet: 1.7.1 - maplibre-gl: 2.4.0 - striptags: 3.2.0 - supercluster: 7.1.5 - three: 0.135.0 - throttle-debounce: 5.0.2 - topojson-client: 3.1.0 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@unovis/vue@1.6.7(@unovis/ts@1.6.7)(vue@3.5.27(typescript@5.9.3))': - dependencies: - '@unovis/ts': 1.6.7 - vue: 3.5.27(typescript@5.9.3) - '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -12034,9 +9194,9 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/nft@1.3.0(rollup@4.57.1)': + '@vercel/nft@1.3.0(rollup@4.57.1)(supports-color@10.2.2)': dependencies: - '@mapbox/node-pre-gyp': 2.0.3 + '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) '@rollup/pluginutils': 5.3.0(rollup@4.57.1) acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) @@ -12058,13 +9218,13 @@ snapshots: '@formatjs/intl': 2.10.15(typescript@5.9.3) intl-messageformat: 10.7.18 - '@vitejs/plugin-vue-jsx@5.1.4(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue-jsx@5.1.4(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2)) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@rolldown/pluginutils': 1.0.0-rc.12 - '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0) + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: @@ -12075,11 +9235,6 @@ snapshots: vite: 5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) vue: 3.5.27(typescript@5.9.3) - '@vitejs/plugin-vue@5.2.4(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': - dependencies: - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vue: 3.5.27(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 @@ -12092,48 +9247,6 @@ snapshots: vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) - '@vitest/expect@3.2.7': - dependencies: - '@types/chai': 5.2.3 - '@vitest/spy': 3.2.7 - '@vitest/utils': 3.2.7 - chai: 5.3.3 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.2.7(vite@5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0))': - dependencies: - '@vitest/spy': 3.2.7 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - - '@vitest/pretty-format@3.2.7': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.2.7': - dependencies: - '@vitest/utils': 3.2.7 - pathe: 2.0.3 - strip-literal: 3.1.0 - - '@vitest/snapshot@3.2.7': - dependencies: - '@vitest/pretty-format': 3.2.7 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@3.2.7': - dependencies: - tinyspy: 4.0.4 - - '@vitest/utils@3.2.7': - dependencies: - '@vitest/pretty-format': 3.2.7 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - '@volar/language-core@2.4.15': dependencies: '@volar/source-map': 2.4.15 @@ -12146,11 +9259,13 @@ snapshots: '@volar/source-map@2.4.27': {} - '@volar/typescript@2.4.15': + '@volar/typescript@2.4.15(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 path-browserify: 1.0.1 vscode-uri: 3.1.0 + optionalDependencies: + typescript: 5.9.3 '@vue-macros/common@3.1.2(vue@3.5.27(typescript@5.9.3))': dependencies: @@ -12166,54 +9281,54 @@ snapshots: '@vue/babel-helper-vue-transform-on@2.0.1': {} - '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/helper-module-imports': 7.28.6 + '@babel/helper-module-imports': 7.28.6(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2)) '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0) + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@vue/shared': 3.5.27 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0)': + '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/helper-module-imports': 7.28.6 + '@babel/helper-module-imports': 7.28.6(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2)) '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@10.2.2) '@babel/types': 7.29.0 '@vue/babel-helper-vue-transform-on': 2.0.1 - '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.0) + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@vue/shared': 3.5.27 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-module-imports': 7.28.6(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 '@babel/parser': 7.29.0 '@vue/compiler-sfc': 3.5.27 transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.0)': + '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/helper-module-imports': 7.28.6(supports-color@10.2.2) '@babel/helper-plugin-utils': 7.28.6 '@babel/parser': 7.29.0 '@vue/compiler-sfc': 3.5.27 @@ -12222,7 +9337,7 @@ snapshots: '@vue/compiler-core@3.5.27': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.8 '@vue/shared': 3.5.27 entities: 7.0.1 estree-walker: 2.0.2 @@ -12261,14 +9376,14 @@ snapshots: dependencies: '@vue/devtools-kit': 7.7.9 - '@vue/devtools-core@8.0.5(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': + '@vue/devtools-core@8.0.5(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: '@vue/devtools-kit': 8.0.5 '@vue/devtools-shared': 8.0.5 mitt: 3.0.1 nanoid: 5.1.6 pathe: 2.0.3 - vite-hot-client: 2.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - vite @@ -12363,15 +9478,6 @@ snapshots: '@vue/shared@3.5.27': {} - '@vue/test-utils@2.4.11(@vue/compiler-dom@3.5.27)(@vue/server-renderer@3.5.27(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))': - dependencies: - '@vue/compiler-dom': 3.5.27 - js-beautify: 1.15.4 - vue: 3.5.27(typescript@5.9.3) - vue-component-type-helpers: 3.2.4 - optionalDependencies: - '@vue/server-renderer': 3.5.27(vue@3.5.27(typescript@5.9.3)) - '@vue/tsconfig@0.7.0(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))': optionalDependencies: typescript: 5.9.3 @@ -12396,13 +9502,6 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/core@14.4.0(vue@3.5.27(typescript@5.9.3))': - dependencies: - '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.4.0 - '@vueuse/shared': 14.4.0(vue@3.5.27(typescript@5.9.3)) - vue: 3.5.27(typescript@5.9.3) - '@vueuse/core@9.13.0(vue@3.5.27(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.16 @@ -12417,8 +9516,6 @@ snapshots: '@vueuse/metadata@12.8.2': {} - '@vueuse/metadata@14.4.0': {} - '@vueuse/metadata@9.13.0': {} '@vueuse/shared@11.3.0(vue@3.5.27(typescript@5.9.3))': @@ -12434,10 +9531,6 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/shared@14.4.0(vue@3.5.27(typescript@5.9.3))': - dependencies: - vue: 3.5.27(typescript@5.9.3) - '@vueuse/shared@9.13.0(vue@3.5.27(typescript@5.9.3))': dependencies: vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) @@ -12459,8 +9552,6 @@ snapshots: '@yr/monotone-cubic-spline@1.0.3': {} - abbrev@2.0.0: {} - abbrev@3.0.1: {} abort-controller@3.0.0: @@ -12477,15 +9568,11 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-walk@8.3.2: {} - - acorn@8.14.0: {} - acorn@8.15.0: {} - agent-base@6.0.2: + agent-base@6.0.2(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -12559,12 +9646,6 @@ snapshots: argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - assertion-error@2.0.1: {} - ast-kit@2.2.0: dependencies: '@babel/parser': 7.29.0 @@ -12599,11 +9680,11 @@ snapshots: postcss: 8.5.8 postcss-value-parser: 4.2.0 - axios@1.16.1: + axios@1.16.1(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - follow-redirects: 1.16.0 + follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2)) form-data: 4.0.5 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@10.2.2) proxy-from-env: 2.1.0 transitivePeerDependencies: - debug @@ -12611,12 +9692,6 @@ snapshots: b4a@1.7.3: {} - babel-plugin-macros@3.1.0: - dependencies: - '@babel/runtime': 7.29.7 - cosmiconfig: 7.1.0 - resolve: 1.22.11 - balanced-match@1.0.2: {} bare-events@2.8.2: {} @@ -12631,16 +9706,10 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - birpc@0.2.14: {} - birpc@2.9.0: {} - blake3-wasm@2.1.5: {} - boolbase@1.0.0: {} - bowser@2.14.1: {} - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -12681,7 +9750,7 @@ snapshots: dependencies: chokidar: 5.0.0 confbox: 0.2.2 - defu: 6.1.4 + defu: 6.1.7 dotenv: 17.2.3 exsolve: 1.0.8 giget: 2.0.0 @@ -12723,14 +9792,6 @@ snapshots: caniuse-lite@1.0.30001767: {} - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -12740,8 +9801,6 @@ snapshots: charenc@0.0.2: {} - check-error@2.1.3: {} - chevrotain@7.1.1: dependencies: regexp-to-ast: 0.5.0 @@ -12778,12 +9837,6 @@ snapshots: citty@0.2.0: {} - cjs-module-lexer@1.4.3: {} - - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -12800,8 +9853,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clsx@2.1.1: {} - cluster-key-slot@1.1.2: {} color-convert@2.0.1: @@ -12810,24 +9861,12 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.4 - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - colord@2.9.3: {} combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - commander@10.0.1: {} - commander@11.1.0: {} commander@2.20.3: {} @@ -12858,23 +9897,14 @@ snapshots: confbox@0.2.2: {} - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - consola@3.4.2: {} - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} cookie-es@1.2.2: {} cookie-es@2.0.0: {} - cookie@1.1.1: {} - copy-anything@4.0.5: dependencies: is-what: 5.5.0 @@ -12889,14 +9919,6 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig@7.1.0: - dependencies: - '@types/parse-json': 4.0.2 - import-fresh: 3.3.1 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.3 - crc-32@1.2.2: {} crc32-stream@6.0.0: @@ -12957,8 +9979,6 @@ snapshots: css-what@6.2.2: {} - csscolorparser@1.0.3: {} - cssesc@3.0.0: {} cssfilter@0.0.10: {} @@ -13013,183 +10033,6 @@ snapshots: csstype@3.2.3: {} - d3-array@2.12.1: - dependencies: - internmap: 1.0.1 - - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-axis@3.0.0: {} - - d3-brush@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3-chord@3.0.1: - dependencies: - d3-path: 3.1.0 - - d3-collection@1.0.7: {} - - d3-color@3.1.0: {} - - d3-contour@4.0.2: - dependencies: - d3-array: 3.2.4 - - d3-delaunay@6.0.4: - dependencies: - delaunator: 5.1.0 - - d3-dispatch@3.0.1: {} - - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - - d3-dsv@3.0.1: - dependencies: - commander: 7.2.0 - iconv-lite: 0.6.3 - rw: 1.3.3 - - d3-ease@3.0.1: {} - - d3-fetch@3.0.1: - dependencies: - d3-dsv: 3.0.1 - - d3-force@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - - d3-format@3.1.2: {} - - d3-geo-projection@4.0.0: - dependencies: - commander: 7.2.0 - d3-array: 3.2.4 - d3-geo: 3.1.1 - - d3-geo@3.1.1: - dependencies: - d3-array: 3.2.4 - - d3-hierarchy@3.1.2: {} - - d3-interpolate-path@2.3.0: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@1.0.9: {} - - d3-path@3.1.0: {} - - d3-polygon@3.0.1: {} - - d3-quadtree@3.0.1: {} - - d3-random@3.0.1: {} - - d3-sankey@0.12.3: - dependencies: - d3-array: 2.12.1 - d3-shape: 1.3.7 - - d3-scale-chromatic@3.1.0: - dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-selection@3.0.0: {} - - d3-shape@1.3.7: - dependencies: - d3-path: 1.0.9 - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3@7.9.0: - dependencies: - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.2 - d3-delaunay: 6.0.4 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.2 - d3-geo: 3.1.1 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.1.0 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 - dayjs@1.11.19: {} db0@0.3.4: {} @@ -13198,14 +10041,14 @@ snapshots: debounce@1.2.1: {} - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decimal.js@10.6.0: {} - deep-eql@5.0.2: {} - deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -13231,10 +10074,6 @@ snapshots: defu@6.1.7: {} - delaunator@5.1.0: - dependencies: - robust-predicates: 3.0.3 - delayed-stream@1.0.0: {} denque@2.1.0: {} @@ -13299,23 +10138,12 @@ snapshots: duplexer@0.1.2: {} - earcut@2.2.4: {} - eastasianwidth@0.2.0: {} - editorconfig@1.0.7: - dependencies: - '@one-ini/wasm': 0.1.1 - commander: 10.0.1 - minimatch: 9.0.5 - semver: 7.8.5 - ee-first@1.1.1: {} electron-to-chromium@1.5.286: {} - elkjs@0.10.2: {} - emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -13349,8 +10177,6 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} - es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: @@ -13392,34 +10218,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.25.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.4 - '@esbuild/android-arm': 0.25.4 - '@esbuild/android-arm64': 0.25.4 - '@esbuild/android-x64': 0.25.4 - '@esbuild/darwin-arm64': 0.25.4 - '@esbuild/darwin-x64': 0.25.4 - '@esbuild/freebsd-arm64': 0.25.4 - '@esbuild/freebsd-x64': 0.25.4 - '@esbuild/linux-arm': 0.25.4 - '@esbuild/linux-arm64': 0.25.4 - '@esbuild/linux-ia32': 0.25.4 - '@esbuild/linux-loong64': 0.25.4 - '@esbuild/linux-mips64el': 0.25.4 - '@esbuild/linux-ppc64': 0.25.4 - '@esbuild/linux-riscv64': 0.25.4 - '@esbuild/linux-s390x': 0.25.4 - '@esbuild/linux-x64': 0.25.4 - '@esbuild/netbsd-arm64': 0.25.4 - '@esbuild/netbsd-x64': 0.25.4 - '@esbuild/openbsd-arm64': 0.25.4 - '@esbuild/openbsd-x64': 0.25.4 - '@esbuild/sunos-x64': 0.25.4 - '@esbuild/win32-arm64': 0.25.4 - '@esbuild/win32-ia32': 0.25.4 - '@esbuild/win32-x64': 0.25.4 - esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -13479,35 +10277,6 @@ snapshots: '@esbuild/win32-x64': 0.27.3 optional: true - esbuild@0.28.1: - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.1 - '@esbuild/android-arm': 0.28.1 - '@esbuild/android-arm64': 0.28.1 - '@esbuild/android-x64': 0.28.1 - '@esbuild/darwin-arm64': 0.28.1 - '@esbuild/darwin-x64': 0.28.1 - '@esbuild/freebsd-arm64': 0.28.1 - '@esbuild/freebsd-x64': 0.28.1 - '@esbuild/linux-arm': 0.28.1 - '@esbuild/linux-arm64': 0.28.1 - '@esbuild/linux-ia32': 0.28.1 - '@esbuild/linux-loong64': 0.28.1 - '@esbuild/linux-mips64el': 0.28.1 - '@esbuild/linux-ppc64': 0.28.1 - '@esbuild/linux-riscv64': 0.28.1 - '@esbuild/linux-s390x': 0.28.1 - '@esbuild/linux-x64': 0.28.1 - '@esbuild/netbsd-arm64': 0.28.1 - '@esbuild/netbsd-x64': 0.28.1 - '@esbuild/openbsd-arm64': 0.28.1 - '@esbuild/openbsd-x64': 0.28.1 - '@esbuild/openharmony-arm64': 0.28.1 - '@esbuild/sunos-x64': 0.28.1 - '@esbuild/win32-arm64': 0.28.1 - '@esbuild/win32-ia32': 0.28.1 - '@esbuild/win32-x64': 0.28.1 - escalade@3.2.0: {} escape-html@1.0.3: {} @@ -13518,21 +10287,21 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@1.21.7)): + eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)): dependencies: - '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@1.21.7)) - eslint: 9.39.2(jiti@1.21.7) + '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) find-up-simple: 1.0.1 - eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@2.6.1)): + eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) find-up-simple: 1.0.1 - eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-flat-config-utils@0.4.0: dependencies: @@ -13545,12 +10314,12 @@ snapshots: optionalDependencies: unrs-resolver: 1.11.1 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@typescript-eslint/types': 8.54.0 comment-parser: 1.4.5 - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.1.2 @@ -13558,16 +10327,16 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-import-x@4.16.1(@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)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@typescript-eslint/types': 8.54.0 comment-parser: 1.4.5 - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.1.2 @@ -13575,18 +10344,18 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/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)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@es-joy/jsdoccomment': 0.50.2 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) espree: 10.4.0 esquery: 1.7.0 parse-imports-exports: 0.2.4 @@ -13595,14 +10364,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@es-joy/jsdoccomment': 0.50.2 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) espree: 10.4.0 esquery: 1.7.0 parse-imports-exports: 0.2.4 @@ -13611,61 +10380,61 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(prettier@3.8.1): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) prettier: 3.8.1 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) - eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.5 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) jsdoc-type-pratt-parser: 4.8.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.5 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) jsdoc-type-pratt-parser: 4.8.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) - eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@1.21.7))(turbo@2.8.2): + eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(turbo@2.8.2): dependencies: dotenv: 16.0.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) turbo: 2.8.2 - eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.2): + eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(turbo@2.8.2): dependencies: dotenv: 16.0.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) turbo: 2.8.2 - eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) ci-info: 4.4.0 clean-regexp: 1.0.0 core-js-compat: 3.48.0 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) esquery: 1.7.0 globals: 15.15.0 indent-string: 4.0.0 @@ -13678,14 +10447,14 @@ snapshots: semver: 7.7.4 strip-indent: 3.0.0 - eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) ci-info: 4.4.0 clean-regexp: 1.0.0 core-js-compat: 3.48.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) esquery: 1.7.0 globals: 15.15.0 indent-string: 4.0.0 @@ -13698,44 +10467,44 @@ snapshots: semver: 7.7.4 strip-indent: 3.0.0 - eslint-plugin-vue@10.7.0(@stylistic/eslint-plugin@2.13.0(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))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue@10.7.0(@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 semver: 7.7.3 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 2.13.0(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) + '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) - eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) - eslint: 9.39.2(jiti@1.21.7) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.4 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color - eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.4 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -13754,14 +10523,14 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@1.21.7): + eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.1(supports-color@10.2.2) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 + '@eslint/eslintrc': 3.3.3(supports-color@10.2.2) '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 @@ -13771,7 +10540,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -13795,14 +10564,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@9.39.2(jiti@2.6.1): + eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.1(supports-color@10.2.2) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 + '@eslint/eslintrc': 3.3.3(supports-color@10.2.2) '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 @@ -13812,7 +10581,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -13900,10 +10669,6 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 - exit-hook@2.2.1: {} - - expect-type@1.4.0: {} - exsolve@1.0.8: {} externality@1.0.2: @@ -13955,8 +10720,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-root@1.1.0: {} - find-up-simple@1.0.1: {} find-up@4.1.0: @@ -13986,7 +10749,9 @@ snapshots: optionalDependencies: '@nuxt/kit': 3.21.0(magicast@0.5.1) - follow-redirects@1.16.0: {} + follow-redirects@1.16.0(debug@4.4.3(supports-color@10.2.2)): + optionalDependencies: + debug: 4.4.3(supports-color@10.2.2) foreground-child@3.3.1: dependencies: @@ -14025,10 +10790,6 @@ snapshots: gensync@1.0.0-beta.2: {} - geojson-vt@3.2.1: {} - - geojson@0.5.0: {} - get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -14055,8 +10816,6 @@ snapshots: dependencies: pump: 3.0.3 - get-stream@6.0.1: {} - get-stream@8.0.1: {} get-tsconfig@4.13.1: @@ -14067,7 +10826,7 @@ snapshots: dependencies: citty: 0.1.6 consola: 3.4.2 - defu: 6.1.4 + defu: 6.1.7 node-fetch-native: 1.6.7 nypm: 0.6.4 pathe: 2.0.3 @@ -14091,8 +10850,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -14112,12 +10869,6 @@ snapshots: dependencies: ini: 4.1.1 - global-prefix@3.0.0: - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -14165,12 +10916,6 @@ snapshots: ufo: 1.6.3 uncrypto: 0.1.3 - happy-dom@18.0.1: - dependencies: - '@types/node': 20.19.43 - '@types/whatwg-mimetype': 3.0.2 - whatwg-mimetype: 3.0.0 - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -14191,18 +10936,12 @@ snapshots: highlightjs-mcfunction@https://codeload.github.com/modrinth/better-highlightjs-mcfunction/tar.gz/aa999b763fd792ffb950d28347eeb6811c83ea8e: {} - hono@4.13.1: {} - hookable@5.5.3: {} hookable@6.0.1: {} hosted-git-info@2.8.9: {} - howxm-js@0.0.10(react@19.2.4): - dependencies: - react: 19.2.4 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -14213,17 +10952,17 @@ snapshots: http-shutdown@1.2.2: {} - https-proxy-agent@5.0.1: + https-proxy-agent@5.0.1(supports-color@10.2.2): dependencies: - agent-base: 6.0.2 - debug: 4.4.3 + agent-base: 6.0.2(supports-color@10.2.2) + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -14235,10 +10974,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ieee754@1.2.1: {} if-ci@3.0.0: @@ -14275,16 +11010,10 @@ snapshots: inherits@2.0.4: {} - ini@1.3.8: {} - ini@4.1.1: {} ini@6.0.0: {} - internmap@1.0.1: {} - - internmap@2.0.3: {} - intl-messageformat@10.7.18: dependencies: '@formatjs/ecma402-abstract': 2.3.6 @@ -14299,11 +11028,11 @@ snapshots: '@formatjs/icu-messageformat-parser': 2.9.4 tslib: 2.8.1 - ioredis@5.9.2: + ioredis@5.9.2(supports-color@10.2.2): dependencies: '@ioredis/commands': 1.5.0 cluster-key-slot: 1.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -14317,8 +11046,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.4: {} - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -14410,18 +11137,6 @@ snapshots: jiti@2.6.1: {} - jose@6.2.8: {} - - js-beautify@1.15.4: - dependencies: - config-chain: 1.1.13 - editorconfig: 1.0.7 - glob: 10.5.0 - js-cookie: 3.0.8 - nopt: 7.2.1 - - js-cookie@3.0.8: {} - js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -14452,11 +11167,9 @@ snapshots: dependencies: lie: 3.3.0 pako: 1.0.11 - readable-stream: 2.3.8(patch_hash=3045f7adf989b4e668a4a13819b7285b0de186b79bbf22408acaf2a41c6eaa86) + readable-stream: 2.3.8 setimmediate: 1.0.5 - kdbush@3.0.0: {} - keep-a-changelog@3.0.2: dependencies: ini: 6.0.0 @@ -14466,8 +11179,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - kind-of@6.0.3: {} - kleur@3.0.3: {} kleur@4.1.5: {} @@ -14485,9 +11196,7 @@ snapshots: lazystream@1.0.1: dependencies: - readable-stream: 2.3.8(patch_hash=3045f7adf989b4e668a4a13819b7285b0de186b79bbf22408acaf2a41c6eaa86) - - leaflet@1.7.1: {} + readable-stream: 2.3.8 levn@0.4.1: dependencies: @@ -14648,8 +11357,6 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.18.1: {} - lodash.defaults@4.2.0: {} lodash.isarguments@3.1.0: {} @@ -14662,8 +11369,6 @@ snapshots: lodash@4.17.23: {} - loupe@3.2.1: {} - lru-cache@10.4.3: {} lru-cache@11.2.5: {} @@ -14674,10 +11379,6 @@ snapshots: lucide-static@0.562.0: {} - lucide-vue-next@0.468.0(vue@3.5.27(typescript@5.9.3)): - dependencies: - vue: 3.5.27(typescript@5.9.3) - magic-regexp@0.10.0: dependencies: estree-walker: 3.0.3 @@ -14698,37 +11399,10 @@ snapshots: magicast@0.5.1: dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 source-map-js: 1.2.1 - maplibre-gl@2.4.0: - dependencies: - '@mapbox/geojson-rewind': 0.5.2 - '@mapbox/jsonlint-lines-primitives': 2.0.3 - '@mapbox/mapbox-gl-supported': 2.0.1 - '@mapbox/point-geometry': 0.1.0 - '@mapbox/tiny-sdf': 2.2.0 - '@mapbox/unitbezier': 0.0.1 - '@mapbox/vector-tile': 1.3.1 - '@mapbox/whoots-js': 3.1.0 - '@types/geojson': 7946.0.16 - '@types/mapbox__point-geometry': 0.1.4 - '@types/mapbox__vector-tile': 1.3.4 - '@types/pbf': 3.0.5 - csscolorparser: 1.0.3 - earcut: 2.2.4 - geojson-vt: 3.2.1 - gl-matrix: 3.4.4 - global-prefix: 3.0.0 - murmurhash-js: 1.0.0 - pbf: 3.3.0 - potpack: 1.0.2 - quickselect: 2.0.0 - supercluster: 7.1.5 - tinyqueue: 2.0.3 - vt-pbf: 3.1.3 - markdown-it@13.0.2: dependencies: argparse: 2.0.1 @@ -14789,44 +11463,12 @@ snapshots: dependencies: mime-db: 1.54.0 - mime@3.0.0: {} - mime@4.1.0: {} mimic-fn@4.0.0: {} min-indent@1.0.1: {} - miniflare@4.20250906.0: - dependencies: - '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.2 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - sharp: 0.33.5 - stoppable: 1.1.0 - undici: 7.29.0 - workerd: 1.20250906.0 - ws: 8.18.0 - youch: 4.1.0-beta.10 - zod: 3.22.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - miniflare@5.20260801.0-alpha: - dependencies: - '@cspotcode/source-map-support': 0.8.1 - sharp: 0.35.2 - undici: 7.28.0 - workerd: 1.20260801.1 - ws: 8.21.0 - youch: 4.1.0-beta.10 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - minimatch@10.1.2: dependencies: '@isaacs/brace-expansion': 5.0.1 @@ -14843,8 +11485,6 @@ snapshots: dependencies: brace-expansion: 2.0.2 - minimist@1.2.8: {} - minipass@7.1.2: {} minizlib@3.1.0: @@ -14892,8 +11532,6 @@ snapshots: muggle-string@0.4.1: {} - murmurhash-js@1.0.0: {} - mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -14912,7 +11550,7 @@ snapshots: nice-try@1.0.5: {} - nitropack@2.13.1(rolldown@1.0.0-rc.12)(xml2js@0.6.2): + nitropack@2.13.1(rolldown@1.0.0-rc.12)(supports-color@10.2.2)(xml2js@0.6.2): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 '@rollup/plugin-alias': 6.0.0(rollup@4.57.1) @@ -14922,7 +11560,7 @@ snapshots: '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1) '@rollup/plugin-replace': 6.0.3(rollup@4.57.1) '@rollup/plugin-terser': 0.4.4(rollup@4.57.1) - '@vercel/nft': 1.3.0(rollup@4.57.1) + '@vercel/nft': 1.3.0(rollup@4.57.1)(supports-color@10.2.2) archiver: 7.0.1 c12: 3.3.3(magicast@0.5.1) chokidar: 5.0.0 @@ -14946,7 +11584,7 @@ snapshots: h3: 1.15.5 hookable: 5.5.3 httpxy: 0.1.7 - ioredis: 5.9.2 + ioredis: 5.9.2(supports-color@10.2.2) jiti: 2.6.1 klona: 2.0.6 knitwork: 1.3.0 @@ -14969,7 +11607,7 @@ snapshots: scule: 1.3.0 semver: 7.8.5 serve-placeholder: 2.0.2 - serve-static: 2.2.1 + serve-static: 2.2.1(supports-color@10.2.2) source-map: 0.7.6 std-env: 3.10.0 ufo: 1.6.3 @@ -14979,7 +11617,7 @@ snapshots: unenv: 2.0.0-rc.24 unimport: 5.6.0 unplugin-utils: 0.3.1 - unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2) + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.9.2(supports-color@10.2.2)) untyped: 2.0.0 unwasm: 0.5.3 youch: 4.1.0-beta.13 @@ -15032,10 +11670,6 @@ snapshots: node-releases@2.0.27: {} - nopt@7.2.1: - dependencies: - abbrev: 2.0.0 - nopt@8.1.0: dependencies: abbrev: 3.0.1 @@ -15066,16 +11700,16 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2): + nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2): dependencies: '@dxup/nuxt': 0.2.2(magicast@0.5.1) - '@nuxt/cli': 3.32.0(cac@6.7.14)(magicast@0.5.1) - '@nuxt/devtools': 3.1.1(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + '@nuxt/cli': 3.32.0(cac@6.7.14)(magicast@0.5.1)(supports-color@10.2.2) + '@nuxt/devtools': 3.1.1(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) '@nuxt/kit': 3.20.2(magicast@0.5.1) - '@nuxt/nitro-server': 3.20.2(db0@0.3.4)(ioredis@5.9.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(rolldown@1.0.0-rc.12)(typescript@5.9.3)(xml2js@0.6.2) + '@nuxt/nitro-server': 3.20.2(db0@0.3.4)(ioredis@5.9.2(supports-color@10.2.2))(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(rolldown@1.0.0-rc.12)(supports-color@10.2.2)(typescript@5.9.3)(xml2js@0.6.2) '@nuxt/schema': 3.20.2 '@nuxt/telemetry': 2.6.6(magicast@0.5.1) - '@nuxt/vite-builder': 3.20.2(@types/node@24.12.2)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.32.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.27(typescript@5.9.3))(yaml@2.8.2) + '@nuxt/vite-builder': 3.20.2(@types/node@24.12.2)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.6)(@types/node@24.12.2)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(ioredis@5.9.2(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.1)(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rolldown@1.0.0-rc.12)(rollup@4.57.1)(sass@1.97.3)(supports-color@10.2.2)(terser@5.46.0)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.27(typescript@5.9.3))(yaml@2.8.2) '@unhead/vue': 2.1.2(vue@3.5.27(typescript@5.9.3)) '@vue/shared': 3.5.27 c12: 3.3.3(magicast@0.5.1) @@ -15388,21 +12022,10 @@ snapshots: lru-cache: 11.2.5 minipass: 7.1.2 - path-to-regexp@6.3.0: {} - - path-type@4.0.0: {} - pathe@1.1.2: {} pathe@2.0.3: {} - pathval@2.0.1: {} - - pbf@3.3.0: - dependencies: - ieee754: 1.2.1 - resolve-protobuf-schema: 2.1.0 - perfect-debounce@1.0.0: {} perfect-debounce@2.1.0: {} @@ -15675,10 +12298,6 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - proto-list@1.2.4: {} - - protocol-buffers-schema@3.6.1: {} - protocols@2.0.2: {} proxy-from-env@2.1.0: {} @@ -15704,8 +12323,6 @@ snapshots: queue-microtask@1.2.3: {} - quickselect@2.0.0: {} - radix3@1.1.2: {} randombytes@2.1.0: @@ -15716,7 +12333,7 @@ snapshots: rc9@2.1.2: dependencies: - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 react-dom@19.2.4(react@19.2.4): @@ -15725,7 +12342,8 @@ snapshots: scheduler: 0.27.0 optional: true - react@19.2.4: {} + react@19.2.4: + optional: true read-cache@1.0.0: dependencies: @@ -15751,7 +12369,7 @@ snapshots: isarray: 0.0.1 string_decoder: 0.10.31 - readable-stream@2.3.8(patch_hash=3045f7adf989b4e668a4a13819b7285b0de186b79bbf22408acaf2a41c6eaa86): + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 inherits: 2.0.4 @@ -15804,22 +12422,6 @@ snapshots: dependencies: jsesc: 0.5.0 - reka-ui@2.10.1(vue@3.5.27(typescript@5.9.3)): - dependencies: - '@floating-ui/dom': 1.8.0 - '@floating-ui/vue': 1.1.11(vue@3.5.27(typescript@5.9.3)) - '@internationalized/date': 3.12.3 - '@internationalized/number': 3.6.7 - '@tanstack/vue-virtual': 3.13.35(vue@3.5.27(typescript@5.9.3)) - '@vueuse/core': 14.4.0(vue@3.5.27(typescript@5.9.3)) - '@vueuse/shared': 14.4.0(vue@3.5.27(typescript@5.9.3)) - aria-hidden: 1.2.6 - defu: 6.1.7 - ohash: 2.0.11 - vue: 3.5.27(typescript@5.9.3) - transitivePeerDependencies: - - '@vue/composition-api' - remove-accents@0.5.0: {} require-directory@2.1.1: {} @@ -15832,10 +12434,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve-protobuf-schema@2.1.0: - dependencies: - protocol-buffers-schema: 3.6.1 - resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -15846,8 +12444,6 @@ snapshots: rfdc@1.4.1: {} - robust-predicates@3.0.3: {} - rolldown@1.0.0-rc.12: dependencies: '@oxc-project/types': 0.122.0 @@ -15916,8 +12512,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rw@1.3.3: {} - safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -15955,9 +12549,9 @@ snapshots: semver@7.8.5: {} - send@1.2.1: + send@1.2.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -15981,12 +12575,12 @@ snapshots: dependencies: defu: 6.1.4 - serve-static@2.2.1: + serve-static@2.2.1(supports-color@10.2.2): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1 + send: 1.2.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -15994,64 +12588,6 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.33.5: - dependencies: - color: 4.2.3 - detect-libc: 2.1.2 - semver: 7.8.5 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 - - sharp@0.35.2: - dependencies: - '@img/colour': 1.1.0 - detect-libc: 2.1.2 - semver: 7.8.5 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.35.2 - '@img/sharp-darwin-x64': 0.35.2 - '@img/sharp-freebsd-wasm32': 0.35.2 - '@img/sharp-libvips-darwin-arm64': 1.3.1 - '@img/sharp-libvips-darwin-x64': 1.3.1 - '@img/sharp-libvips-linux-arm': 1.3.1 - '@img/sharp-libvips-linux-arm64': 1.3.1 - '@img/sharp-libvips-linux-ppc64': 1.3.1 - '@img/sharp-libvips-linux-riscv64': 1.3.1 - '@img/sharp-libvips-linux-s390x': 1.3.1 - '@img/sharp-libvips-linux-x64': 1.3.1 - '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 - '@img/sharp-libvips-linuxmusl-x64': 1.3.1 - '@img/sharp-linux-arm': 0.35.2 - '@img/sharp-linux-arm64': 0.35.2 - '@img/sharp-linux-ppc64': 0.35.2 - '@img/sharp-linux-riscv64': 0.35.2 - '@img/sharp-linux-s390x': 0.35.2 - '@img/sharp-linux-x64': 0.35.2 - '@img/sharp-linuxmusl-arm64': 0.35.2 - '@img/sharp-linuxmusl-x64': 0.35.2 - '@img/sharp-webcontainers-wasm32': 0.35.2 - '@img/sharp-win32-arm64': 0.35.2 - '@img/sharp-win32-ia32': 0.35.2 - '@img/sharp-win32-x64': 0.35.2 - shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 @@ -16094,24 +12630,18 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} - signal-exit@3.0.7: {} signal-exit@4.1.0: {} - simple-git@3.30.0: + simple-git@3.30.0(supports-color@10.2.2): dependencies: - '@kwsites/file-exists': 1.1.1 + '@kwsites/file-exists': 1.1.1(supports-color@10.2.2) '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - simple-swizzle@0.2.4: - dependencies: - is-arrayish: 0.3.4 - sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -16133,8 +12663,6 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 - source-map@0.5.7: {} - source-map@0.6.1: {} source-map@0.7.6: {} @@ -16166,8 +12694,6 @@ snapshots: stable-hash-x@0.2.0: {} - stackback@0.0.2: {} - standard-as-callback@2.1.0: {} stats-gl@2.4.2(@types/three@0.172.0)(three@0.172.0): @@ -16181,8 +12707,6 @@ snapshots: std-env@3.10.0: {} - stoppable@1.1.0: {} - streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -16242,8 +12766,6 @@ snapshots: optionalDependencies: '@types/node': 24.12.2 - striptags@3.2.0: {} - structured-clone-es@1.0.0: {} style-mod@4.1.3: {} @@ -16254,8 +12776,6 @@ snapshots: postcss: 8.5.8 postcss-selector-parser: 7.1.1 - stylis@4.2.0: {} - sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -16266,10 +12786,6 @@ snapshots: tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 - supercluster@7.1.5: - dependencies: - kdbush: 3.0.0 - superjson@2.2.6: dependencies: copy-anything: 4.0.5 @@ -16310,8 +12826,6 @@ snapshots: tagged-tag@1.0.0: {} - tailwind-merge@2.6.1: {} - tailwindcss@3.4.19(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 @@ -16402,12 +12916,8 @@ snapshots: potpack: 1.0.2 three: 0.172.0 - three@0.135.0: {} - three@0.172.0: {} - throttle-debounce@5.0.2: {} - through2@0.6.5: dependencies: readable-stream: 1.0.34 @@ -16415,10 +12925,6 @@ snapshots: tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -16426,24 +12932,12 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinypool@1.1.1: {} - - tinyqueue@2.0.3: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.4: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 toidentifier@1.0.1: {} - topojson-client@3.1.0: - dependencies: - commander: 2.20.3 - totalist@3.0.1: {} tr46@0.0.3: {} @@ -16499,13 +12993,13 @@ snapshots: type-level-regexp@0.1.17: {} - typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(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-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.54.0(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -16529,22 +13023,8 @@ snapshots: magic-string: 0.30.21 unplugin: 2.3.11 - undici-types@6.21.0: {} - undici-types@7.16.0: {} - undici@7.28.0: {} - - undici@7.29.0: {} - - unenv@2.0.0-rc.21: - dependencies: - defu: 6.1.4 - exsolve: 1.0.8 - ohash: 2.0.11 - pathe: 2.0.3 - ufo: 1.6.3 - unenv@2.0.0-rc.24: dependencies: pathe: 2.0.3 @@ -16640,7 +13120,7 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - unstorage@1.17.4(db0@0.3.4)(ioredis@5.9.2): + unstorage@1.17.4(db0@0.3.4)(ioredis@5.9.2(supports-color@10.2.2)): dependencies: anymatch: 3.1.3 chokidar: 5.0.0 @@ -16652,7 +13132,7 @@ snapshots: ufo: 1.6.3 optionalDependencies: db0: 0.3.4 - ioredis: 5.9.2 + ioredis: 5.9.2(supports-color@10.2.2) untun@0.1.3: dependencies: @@ -16663,7 +13143,7 @@ snapshots: untyped@2.0.0: dependencies: citty: 0.1.6 - defu: 6.1.4 + defu: 6.1.7 jiti: 2.6.1 knitwork: 1.3.0 scule: 1.3.0 @@ -16696,44 +13176,26 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + birpc: 2.9.0 + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite-dev-rpc@1.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: birpc: 2.9.0 vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vite-hot-client: 2.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) - vite-dev-rpc@1.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: - birpc: 2.9.0 - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-hot-client: 2.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vite-hot-client@2.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-hot-client@2.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): - dependencies: - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - - vite-node@3.2.4(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vite-node@5.3.0(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): dependencies: cac: 6.7.14 @@ -16754,7 +13216,7 @@ snapshots: - tsx - yaml - vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)): + vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)): dependencies: '@babel/code-frame': 7.29.0 chokidar: 4.0.3 @@ -16766,15 +13228,15 @@ snapshots: vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vscode-uri: 3.1.0 optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) optionator: 0.9.4 typescript: 5.9.3 vue-tsc: 2.2.12(typescript@5.9.3) - vite-plugin-inspect@11.3.3(@nuxt/kit@3.21.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + vite-plugin-inspect@11.3.3(@nuxt/kit@3.21.0(magicast@0.5.1))(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: ansis: 4.2.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) error-stack-parser-es: 1.0.5 ohash: 2.0.11 open: 10.2.0 @@ -16788,45 +13250,45 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-inspect@11.3.3(@nuxt/kit@4.3.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + vite-plugin-inspect@11.3.3(@nuxt/kit@4.3.0(magicast@0.5.1))(supports-color@10.2.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: ansis: 4.2.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) error-stack-parser-es: 1.0.5 ohash: 2.0.11 open: 10.2.0 perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-dev-rpc: 1.1.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) optionalDependencies: '@nuxt/kit': 4.3.0(magicast@0.5.1) transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.2.1(@nuxt/kit@3.21.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-devtools@8.2.1(@nuxt/kit@3.21.0(magicast@0.5.1))(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.2.1(vue@3.5.27(typescript@5.9.3)) '@vue/devtools-kit': 8.2.1 '@vue/devtools-shared': 8.2.1 sirv: 3.0.2 vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-plugin-inspect: 11.3.3(@nuxt/kit@3.21.0(magicast@0.5.1))(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) - vite-plugin-vue-inspector: 6.0.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-inspect: 11.3.3(@nuxt/kit@3.21.0(magicast@0.5.1))(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-vue-inspector: 6.0.0(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - '@nuxt/kit' - supports-color - - vue - vite-plugin-vue-inspector@6.0.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + vite-plugin-vue-inspector@6.0.0(supports-color@10.2.2)(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@10.2.2) + '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.0(supports-color@10.2.2)) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0(supports-color@10.2.2)) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0(supports-color@10.2.2))(supports-color@10.2.2) '@vue/compiler-dom': 3.5.27 kolorist: 1.8.0 magic-string: 0.30.21 @@ -16834,14 +13296,14 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-tracer@1.2.0(vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-tracer@1.2.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)): dependencies: estree-walker: 3.0.3 exsolve: 1.0.8 magic-string: 0.30.21 pathe: 2.0.3 source-map-js: 1.2.1 - vite: 8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) vite-svg-loader@5.1.0(vue@3.5.27(typescript@5.9.3)): @@ -16894,69 +13356,8 @@ snapshots: terser: 5.46.0 yaml: 2.8.2 - vite@8.0.3(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.8 - rolldown: 1.0.0-rc.12 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.12.2 - esbuild: 0.27.3 - fsevents: 2.3.3 - jiti: 2.6.1 - sass: 1.97.3 - terser: 5.46.0 - yaml: 2.8.2 - - vitest@3.2.7(@types/node@24.12.2)(happy-dom@18.0.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.7 - '@vitest/mocker': 3.2.7(vite@5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)) - '@vitest/pretty-format': 3.2.7 - '@vitest/runner': 3.2.7 - '@vitest/snapshot': 3.2.7 - '@vitest/spy': 3.2.7 - '@vitest/utils': 3.2.7 - chai: 5.3.3 - debug: 4.4.3 - expect-type: 1.4.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 5.4.21(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - vite-node: 3.2.4(@types/node@24.12.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.12.2 - happy-dom: 18.0.1 - transitivePeerDependencies: - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vscode-uri@3.1.0: {} - vt-pbf@3.1.3: - dependencies: - '@mapbox/point-geometry': 0.1.0 - '@mapbox/vector-tile': 1.3.1 - pbf: 3.3.0 - vue-bundle-renderer@2.2.0: dependencies: ufo: 1.6.3 @@ -16969,10 +13370,10 @@ snapshots: vue-devtools-stub@0.1.0: {} - vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): + vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -16981,10 +13382,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@1.21.7)): + vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@1.21.7)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@1.21.7)(supports-color@10.2.2) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -16994,10 +13395,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@2.6.1)): + vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.2(jiti@2.6.1)(supports-color@10.2.2) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17029,7 +13430,7 @@ snapshots: vue-tsc@2.2.12(typescript@5.9.3): dependencies: - '@volar/typescript': 2.4.15 + '@volar/typescript': 2.4.15(typescript@5.9.3) '@vue/language-core': 2.2.12(typescript@5.9.3) typescript: 5.9.3 @@ -17073,8 +13474,6 @@ snapshots: webpack-virtual-modules@0.6.2: {} - whatwg-mimetype@3.0.0: {} - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -17092,63 +13491,8 @@ snapshots: dependencies: isexe: 3.1.1 - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - word-wrap@1.2.5: {} - workerd@1.20250906.0: - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20250906.0 - '@cloudflare/workerd-darwin-arm64': 1.20250906.0 - '@cloudflare/workerd-linux-64': 1.20250906.0 - '@cloudflare/workerd-linux-arm64': 1.20250906.0 - '@cloudflare/workerd-windows-64': 1.20250906.0 - - workerd@1.20260801.1: - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260801.1 - '@cloudflare/workerd-darwin-arm64': 1.20260801.1 - '@cloudflare/workerd-linux-64': 1.20260801.1 - '@cloudflare/workerd-linux-arm64': 1.20260801.1 - '@cloudflare/workerd-windows-64': 1.20260801.1 - - wrangler@4.119.0(@cloudflare/workers-types@5.20260804.1): - dependencies: - '@cloudflare/kv-asset-handler': 0.5.0 - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260801.1) - blake3-wasm: 2.1.5 - esbuild: 0.28.1 - miniflare: 5.20260801.0-alpha - path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.24 - workerd: 1.20260801.1 - optionalDependencies: - '@cloudflare/workers-types': 5.20260804.1 - fsevents: 2.3.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - wrangler@4.35.0(@cloudflare/workers-types@5.20260804.1): - dependencies: - '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0) - blake3-wasm: 2.1.5 - esbuild: 0.25.4 - miniflare: 4.20250906.0 - path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.21 - workerd: 1.20250906.0 - optionalDependencies: - '@cloudflare/workers-types': 5.20260804.1 - fsevents: 2.3.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -17163,8 +13507,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.0: {} - ws@8.21.0: {} wsl-utils@0.1.0: @@ -17195,8 +13537,6 @@ snapshots: yallist@5.0.0: {} - yaml@1.10.3: {} - yaml@2.8.2: {} yargs-parser@21.1.1: {} @@ -17218,14 +13558,6 @@ snapshots: '@poppinss/exception': 1.2.3 error-stack-parser-es: 1.0.5 - youch@4.1.0-beta.10: - dependencies: - '@poppinss/colors': 4.1.6 - '@poppinss/dumper': 0.6.5 - '@speed-highlight/core': 1.2.14 - cookie: 1.1.1 - youch-core: 0.3.3 - youch@4.1.0-beta.13: dependencies: '@poppinss/colors': 4.1.6 @@ -17239,7 +13571,3 @@ snapshots: archiver-utils: 5.0.2 compress-commons: 6.0.2 readable-stream: 4.7.0 - - zod@3.22.3: {} - - zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d21d086..6de8c0a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,13 @@ packages: - 'apps/*' - 'packages/*' minimumReleaseAge: 10080 # 7 days +allowBuilds: + '@parcel/watcher': true + '@sentry/cli': true + core-js: true + esbuild: true + protobufjs: true + sharp: true + unrs-resolver: true + vue-demi: true + workerd: true